142环形链表
本题的技巧是使用快慢指针
慢指针的移动速度为1,快指针的移动速度为2,如果链表里不存在环,那么快指针会先走到链表末尾(即nullptr)位置。以下我们讨论当链表里存在环的解法。
如图1所示,假设红色点a为链表进入环的第一个节点,蓝色点b为快慢指针相遇的地方。我们假设三段距离分别为
x
x
x,
y
y
y,
z
z
z。假设当快指针追上慢指针时,快指针已经在环内走了
n
n
n圈。则有以下等式成立:
即慢指针走过的路程的两倍等于快指针走过的路程,整理一下可得到:
这个等式具有特殊的含义,它表示如果两个指针分别从链表开始和b节点以相同的速度出发,从b出发的指针在走(n-1)圈之后,最终会在节点a和另一个相遇,而节点a刚好是题目中要求的链表开始入环的第一个节点。
如何找到节点b呢?注意节点b是快慢指针在环里第一次相遇的位置,快指针和满指针相等时的节点位置就是b。
整体代码如下:
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode * slow = head;
ListNode * fast = head;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
// 快慢指针相遇时,即找到b点
if(fast == slow){
ListNode * p = head;
//让p和slow指针同时出发
while(p != slow){
p = p->next;
slow = slow->next;
}
return p;
}
}
return NULL;
}
};
在第一个等式里,为什么慢指针在进入环的第一圈就能和快指针相遇。如果慢指针在进入环时就和快指针相遇,这种情况显然满足在第一圈相遇。我们假设一种比较极端的情况,当慢指针进入环时,快指针刚好在其前方一个节点位置,此时快指针要追赶慢指针,为方便理解,我们把环拉直,如下图所示,每一个线段表示一个环。当慢指针走完一圈时(蓝色线段),由于快指针走的路程是慢指针的两倍,此时快指针的位置一定在慢指针前面(红色线段),在这个过程中,快指针和慢指针一定在某个时刻“擦肩而过”。