题目
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
(判断链表是否有环,请参考环形链表 I)
思路
假设 slow 和 fast (这部分在环形链表 I 中有介绍)在 meet 结点处相遇
先上结论:一个指针从 meet 结点开始走,一个指针从链表开始走,他们会在入口点相遇
推理过程:
slow 走一步,fast 走两步,当 slow 绕环走一圈后,fast 已经走了两圈了
因此,slow 进环了以后,在一圈之内,fast 一定会追上 slow
假设链表中入环结点之前的长度为 L,入环结点到 meet 的长度为 X,环的长度为 C
slow 走的路程为 L+X ,fast 走的路程为 L+N*C+X(当 L 较长,环长 C 较小时,slow 走的慢,slow 走完 L ,fast 可能在环内转了好几圈了,因此这里有个 N*C)
fast 走的路程是 slow 的二倍,即
L+N*C+X = 2 (L+X)
N*C = L+X
(N-1)*C + C = L+X
(N-1)*C + C-X = L
其中 (N-1)*C 是环的整数倍(走完整圈后会回到原地),再走 C-X,总路程等于 L
因此得到:一个指针从 meet 结点开始走,一个指针从链表开始走,他们会在入环点相遇
代码实现
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow = head, * fast = head;
while(fast != NULL && fast->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
struct ListNode* meet = slow;
struct ListNode* cur = head;
while(meet != cur)
{
cur = cur->next;
meet = meet->next;
}
return cur;
}
}
return NULL;
}