selected_coding_interview/docs/142. 环形链表 II.md
K 个节点、寻找环入口、寻找公共尾部入口等。双指针第一次相遇: 设两指针 fast,slow 指向链表头部 head,fast 每轮走 $2$ 步,slow 每轮走 $1$ 步;
第一种结果: fast 指针走过链表末端,说明链表无环,直接返回 null;
fast 与 slow 的间距 $+1$,fast 终会追上 slow;第二种结果: 当fast == slow时, 两指针在环中 第一次相遇 。下面分析此时fast 与 slow走过的 步数关系 :
fast 走的步数是slow步数的 $2$ 倍,即 $f = 2s$;(解析: fast 每轮走 $2$ 步)fast 比 slow多走了 $n$ 个环的长度,即 $f = s + nb$;( 解析: 双指针都走过 $a$ 步,然后在环内绕圈直到重合,重合时 fast 比 slow 多走 环的长度整数倍 );fast和slow 指针分别走了 $2n$,$n$ 个 环的周长 (注意: $n$ 是未知数,不同链表的情况不同)。目前情况分析:
k,那么所有 走到链表入口节点时的步数 是:k=a+nb(先走 $a$ 步到入口节点,之后每绕 $1$ 圈环( $b$ 步)都会再次到入口节点)。slow 指针走过的步数为 $nb$ 步。因此,我们只要想办法让 slow 再走 $a$ 步停下来,就可以到环的入口。slow 一起向前走 a 步后,两者在入口节点重合。那么从哪里走到入口节点需要 $a$ 步?答案是链表头部head。双指针第二次相遇:
slow指针 位置不变 ,将fast指针重新 指向链表头部节点 ;slow和fast同时每轮向前走 $1$ 步;
fast 指针走到$f = a$ 步时,slow 指针走到步$s = a+nb$,此时 两指针重合,并同时指向链表环入口 。返回slow指针指向的节点。
<,,,,,,,,,,>{:width=500} {:align=center}
class Solution(object):
def detectCycle(self, head):
fast, slow = head, head
while True:
if not (fast and fast.next): return
fast, slow = fast.next.next, slow.next
if fast == slow: break
fast = head
while fast != slow:
fast, slow = fast.next, slow.next
return fast
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;
while (true) {
if (fast == null || fast.next == null) return null;
fast = fast.next.next;
slow = slow.next;
if (fast == slow) break;
}
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
}