142.环形链表II
➰ 142.环形链表II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
思路
基本思想
相比于 141题 ,本题不仅需要判断是否有环,还需要将入环的第一个节点给找到,所以增加了难度,在141题的基础上,如果有环,需要增加代码,将入环节点找到
此时有两种解决办法,第一种直接抛弃141题的方式,遍历链表,将链表存储到一个unordered_set中,一旦存储的过程中发现容器中有了此节点,说明找到了第一个入环节点,此方式需要使用容器辅助,增加了空间复杂度
第二周解决办法就是在141题的基础上,通过推导发现数学规律,从而找到入环节点,当找到环时,快慢指针所处的状态如图所示:
此时slow
指针走过的步数为x+y
,fast
指针走过的步数为x+y+n(y+z)
,并且由于快指针走两步慢指针才走一步,所以两个指针步数之间的关系为:
$$
x+y+n(y+z)=2(x+y)
$$
化简之后为:
$$
n(y+z)=x+y
$$
进一步化简为:
$$
(n-1)(y+z)+z=x
$$
也就是说,x和z之间,就差了若干个y+z
,从快慢指针相遇节点和头结点分别出发,再次相遇的节点就是入环节点
执行流程
方法一
- 定义一个
unordered_set
- 遍历链表,尝试将每一个节点加入容器
- 加入之前判断容器中是否已存在当前节点
- 已存在直接返回当前节点,不存在继续遍历
- 遍历到结束都没有找到就返回
nullptr
方法二
- 快慢指针从头出发
- 快指针走两步慢指针走一步
- 当快慢指针相遇时有环
- 从快慢指针和头结点的位置分别出发向后遍历
- 第一个相遇位置就是入环节点
- 没找到环返回
nullptr
代码
根据以上分析,得出以下代码:
方法一
|
|
方法二
|
|
总结
两个方法各有利弊,方法一不需要数学推导,思路简单,但是空间复杂度较高,方法二需要数学推导,但是只需要在判断入环节点位置时