题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/
思路如下:
用两个指针 fast, slow 同时从起点开始走,fast 每次走两步,slow 每次走一步。
如果过程中 fast 走到 null,则说明不存在环。否则当 fast 和 slow 相遇后,让 slow 回到起点,fast 待在原地不动,然后两个指针每次分别走一步,当再次相遇时,相遇点就是环的入口。
证明:
如上图所示,aaa 是起点,bbb 是环的入口,ccc 是两个指针的第一次相遇点,ababab 之间的距离是 xxx,bcbcbc 之间的距离是 yyy,cbcbcb 之间的距离是 zzz。
第一次相遇时,slow 所走的距离是 x+yx+yx+y,fast 所走的距离是 x+(y+z)∗n+yx+(y+z)∗n+yx+(y+z)∗n+y。
因为 fast 走过的距离是 slow 的两倍,所以有 x+(y+z)∗n+y=2(x+y)x+(y+z)∗n+y=2(x+y)x+(y+z)∗n+y=2(x+y),即 x=(n−1)∗(y+z)+zx=(n−1)*(y+z)+zx=(n−1)∗(y+z)+z。
那么我们让 fast 从 ccc 点开始走,走 xxx 步,会恰好走到 bbb 点;让 slow 从 aaa 点开始走,走 xxx 步,也会走到 bbb 点。
C++ 代码如下:
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *detectCycle(ListNode *head) {auto 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;}slow = head;while (fast != slow) {fast = fast->next;slow = slow->next;}return fast;}
};