题意
给定一个链表,判断这个链表内是否存在环,并且求这个环的起点。
思路
如图所示:
我们再假设圆的周长为r,我们需要求的是a。
于是,我们设置两个指针slow和fast,slow每次走一步,fast每次走两步,并且两个都走了t时间,于是:
slow:t=a+b ==>为什么不是t==a+b+mr:因为slow一旦进入环,不会跑超过一圈就会和fast相遇。
fast:2t=a+b+nr
我们可以解得:
nr=a+b
上面式子的意思即:我们从相遇的点C出发,再走a步,能够走到环的起点!即:我们的slow和fast相遇在C点了, 这时候,我们把slow放回起点A,fast放在C点,两个同时开始走且步速均为1,那么我们相遇的点就是B点!
Follow up
求环的长度
首先,我们不能从起点到C点的相遇来确定环长,因为之间相差的是环长的若干倍,并且倍数还不能确定。
但是,当我们第一次在C点相遇后,之后,fast继续走两步,slow继续走一步。再次相遇时,刚好相差一圈。就追及问题。
将有环链表变成单链表
我们找到B点之后,记录下B点的位置,然后绕着环走,再次走到B点时结束。
代码
/**
* 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) {
if (!head) return NULL;
ListNode *slow = head, *fast = head;
while (slow && fast) {
slow = slow->next;
fast = fast->next;
if (!fast) return NULL;
fast = fast->next;
if (slow == fast) break;
}
if (!slow || !fast) return NULL;
slow = head;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return fast;
}
};