环形链表
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
思路: 快慢指针,快指针一次走两步,慢指针一次走一步,如果存在环,快指针会再环内追上慢指针
/**
* 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) {
ListNode *slow = head, *fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast) //如果链表存在环
{
fast = head;
while(fast != slow)//第二次相遇即为环的入口
{
fast = fast->next;
slow = slow->next;
}
return fast;
}
}
return NULL;
}
};
题解
其中【*】为快慢指针首次相遇点,入环前距离为【D】,慢指针入环后走过的距离为【S1】,环剩下距离为【S2】
首次相遇
1.慢指针 S = D + S1
2.快指针 F = D + n(S1 + S2) + S1 其中n>=1,快指针起码走了一圈以上才可能相遇
3.又因为 F = 2S 慢指针走一步,快指针走两步
4.代入1,2 可得 2(D + S1) = D + n(S1 + S2) + S1
各种移项可得 D = (n-1)S1 + nS2 = (n-1)(S1 + S2) + S2
5.其中 n为快指针绕的圈数
n=1 D = S2
n=2 D = 一圈 + S2
n=3 D = 两圈 + S2
…
所以其实我们并不关心绕了多少圈,就知道 n圈+S2就是入环点了
6.人为构造碰撞机会,让快指针重新出发(但这次一次走一步),只要碰撞了,就是入环位置了,管他慢指针在环里绕了多少圈
参考文章
LeetCode 链接