概述
分析
-
技巧类的题目
-
该题可以分为两步:
-
确定链表是否有环; —> 快慢指针法
-
确定环的起始结点
(x+y)*2=(x+y)+n(y+z) //这里n(y+z)是快指针多走的,n代表多做圈数 x=n(y+z)-y=(n-1)(y+z)+z //x是我们要求的 注意到(n-1)(y+z)是环的长度,也就是说,x的长度 = 从指针相遇位置开始的n-1圈 + z 那么 一个指针A从头结点开始,一个指针B从相遇结点开始,同时移动,A会一直向前,B会在环内一直转圈 但是当A走了(n-1)*(y+z)后,B因为环的原因会回到起始位置,此时A、B均还剩z的长度到入口结点,这样当A、Bx
-
思路
为何慢指针第一圈走不完一定会和快指针相遇?
- 可以认为快指针和慢指针是相对运动的,假设慢指针的速度是 1节点/秒,快指针的速度是 2节点/秒,当以慢指针为参考系的话(即慢指针静止),快指针的移动速度就是 1节点/秒,所以肯定会相遇。
为什么在第一圈就会相遇呢?
- 设环的长度为 L,当慢指针刚进入环时,慢指针需要走 L 步(即 L 秒)才能走完一圈,此时快指针距离慢指针的最大距离为 L-1,我们再次以慢指针为参考系,如上所说,快指针在按照1节点/秒的速度在追赶慢指针,所以肯定能在 L 秒内追赶到慢指针。
代码
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *slow = head, *fast = head;
do{
if (!fast || !fast->next) return nullptr; // 无环
fast = fast->next->next; // 快指针,一次移动
slow = slow->next;
}while(slow != fast);
slow = head;
while(slow != fast) {
slow = slow->next;
fast = fast->next;
}
return slow;
}
};