题目
给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next 指针进入环的第一个节点为环的入口节点。如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
- 示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
- 示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
题解
- 思路,快慢指针,如果快指针追上慢指针,证明有环
- 数学推导
首先,如果有环,快指针一定能追上慢指针,假设:
(1)从头节点到入换点距离为a;
(2)从入环点到相遇点距离为b;
(3)相遇点到头节点距离为c;
设快指针追上慢指针时已走了n圈,则有等式
a + (b+c)n + b = 2(a+b);==>a + (n+1)b + nc = 2(a+b); ==> a = c + (n-1)(b+c);
- 由上面等式可知,c的距离等于a的距离
ListNode *detectCycle(ListNode *head) {
//快慢指针 + 数学推理
bool cycle_exist = false;
ListNode* slow = head, *fast = head, *tmp = head;
while(fast != nullptr)
{
if(cycle_exist)
{
// 快指针追上慢指针后,慢指针到入环点的距离 与 头节点到入环点距离相等
if(slow == tmp)
return slow;
slow = slow->next;
tmp = tmp->next;
continue;
}
// 快指针追上慢指针,证明有环
if(fast->next) fast = fast->next->next;
else break;
slow = slow->next;
if(slow == fast) cycle_exist = true;
}
return nullptr;
}