题目解析
找到环的入口
定义快慢指针,f 每次走两步,l 每次走一步,所以 f 走过的节点数是 l 的两倍 f = 2l,如果存在环,那么走的快的 f 和走到慢的 l 会在环上的一点相遇。
设走到环的入口前有a个节点,f 和 l 相遇在环上的第 k 个节点。
当 f 和 l 相遇时:
式1:f 走过的节点数 f = a + n圈 + k
式2:f 走过的节点数 f = a + n1圈 + k ( n1 < n )
又因为 f =2l ,所以根据数学关系 f - l = 2l - l = l = 式1 = 式2 = (n - n1)圈
。
环的入口在哪里?
真好走 a+整数个环
第一次相遇 f 和 l 都正好走了整数个环,所以再走 a 步,到环的入口
怎么正好走 a 步
让 l 回到起点,l 和 f 都一次一步走,相遇时正好在环口,走了 a 步。
( l 从1 走到4,f 从5走到4)
代码实现
public ListNode detectCycle(ListNode head) {
//找到环的入口 正好走 a + x圈
ListNode f = head;
ListNode l = head;
//f 一次走两步 l 一次走1步,当第一次相遇
// f = a + n圈 + k步 = 2l l = a + n1圈 + k步
//f-l=2l-l=l = (n -n1)圈
//找到第一次相遇
while (f != null && f.next != null) {
f = f.next.next;
l = l.next;
if(l == f){
//相遇的f l 在同一个节点
//找到环的入口:此时 l = (n -n1)圈,再走 a 步,正好走到入口
//怎么确定 a? 此时 f=l ,l回到起点,一次都走一步,正好走a步在环口相遇
l = head;
while (l != f){
f = f.next;
l = l.next;
}
return l;
}
}
return null;
}