142 环形链表Ⅱ
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:返回索引为 0 的链表节点 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:返回 null 解释:链表中没有环。
提示:
-
链表中节点的数目范围在范围
[0, 104]
内 -
-105 <= Node.val <= 105
-
pos
的值为-1
或者链表中的一个有效索引
进阶:你是否可以使用 O(1)
空间解决此题?
思路
-
这道题的思路非常有意思,首先,我们还是运用到双指针,一个是快指针,一个是慢指针。
-
快指针一个回合走两步,慢指针一个回合走一步
-
如果在这种情况下,快满指针能够相遇,那么就证明--链表中是存在环结构的
-
如果不能相遇,则可以判定链表中没有环结构
-
在链表中有环结构的前提下,我们快慢指针如果可以相遇,那么就证明此时慢指针也入环了,且慢指针在环内还未能走够一圈
-
为什么呢
环的研究
-
如果慢指针进环时,快指针也位于环的入口处,那么他们这时候距离相差最大,为整整一圈的距离
-
快指针一步走两格,慢指针一步走一格,这样来说就相当于快指针一步走一格,慢指针不动(老高中物理了)
-
在这种情况下,快指针再与慢指针相遇的时候,也仅仅走了一圈,
-
这就说明,慢指针在环内一定没有走够1圈
上图为模拟运行图
-
这样的话,我们就能得到慢指针运动的位移 : x+y
-
快指针的位移是 x + y + n(y+z)
-
2(x+y) = x+y+n(y+z)
-
x+y = n(y+z)
-
x = n(y+z)-y n大于等于1
-
假设n = 1;那么x = z
-
假设n>1 ; 那么 x = n圈 + z
-
在x = z 的情况下时,如果有一个指针从原点出发,一个指针从快慢指针相遇的地方出发,当他们走完x距离后,他们刚好在环的起始节点相遇
-
如果n大于1呢? 他们照样在环的起始节点相遇,只不过第二个指针在环里多转了几圈罢了
-
所以,我们就新建两个指针,一个从起始点出发,一个从相遇位置出发
-
当他们相遇时,我们返回相遇的那个节点
public class Solution { public ListNode detectCycle(ListNode head) { ListNode fastnode = head; ListNode slownode = head; while(fastnode!=null&&slownode!=null) { if(fastnode.next==null||fastnode.next.next==null) { break; } fastnode = fastnode.next.next; slownode = slownode.next; if(fastnode==slownode) { ListNode index1 =head; ListNode index2 = fastnode; while(index1!=index2) { index1 = index1.next; index2 = index2.next; } return index1; } } return null; } }