思路:
与题目141. 环形链表-CSDN博客相似。
先找到快慢指针相遇的位置。
假设从head到环的入口总共有a步,环有b步。
快指针走了 f 步, 慢指针走了 s 步。慢指针走1步,快指针走2步,所以快指针走的步数一定是慢指针的2倍,即 f = 2s。
相遇后,快指针一定比慢指针多走 b 的整数倍步,f = s + nb。
两个式子相减得到 s = nb。
从head走到环入口有 a 步,在走环的整数倍,还能再次到达入口,即 a + nb 也是入口。
因为此时 s 已经是 b 的整数倍了,所以距离入口位置有 a 步。
所以如果从head 和 s 同时开始走,相遇时二者都走了 a 步,相遇的位置就是入口。
总结:
- 走a+nb步一定是在环入口
- 第一次相遇时慢指针已经走了nb步
代码:
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode dummy = new ListNode();
dummy.next = head;
ListNode p1 = dummy, p2 = dummy;
while(p1 != null && p1.next != null) {
p1 = p1.next.next;
p2 = p2.next;
// 相遇了,慢指针p2走了 nb 步
if(p1 == p2) {
ListNode t = dummy;
// t 和 s 同时开始走 相遇时都走了 a 步
while(t != p2) {
t = t.next;
p2 = p2.next;
}
// 相遇的位置就是入口
return t;
}
}
// 快慢指针没有相遇,不存在环
return null;
}
}
参考: