问题:给定一个单向链表,若存在环,则返回环的其实结点,否则返回NULL。
在解这个问题之前,先看个数学问题,或者是体育现象,我们都知道马拉松比赛,运动员需要在体育场外跑一段距离,然后进入体育场跑道。如下草图
设运动员在场外需要跑的路段AB长为k,环形跑道的周长为c,跑道的入口为B,进入后沿跑道顺时针方向跑,现有选手甲乙,乙每秒跑1千米,甲更生猛,每秒跑2千米(有的看官可能会骂:扯淡,你当火箭啊),这不蜗牛都称急速蜗牛了,都跟赛车比赛了,体谅体谅,理解理解。假设甲在距离入口B x 远的D处与乙相遇,那么我们看看k 和 x有什么关系。
甲肯定先到圈里进行循环,等待着乙进入到环里,当乙进入后,甲就有机会追上乙,不会给乙跑完一整圈的机会。
到甲乙相遇的时候,我们知道,甲比乙多跑的距离是环周长的整数倍,而且甲的速度是乙的二倍,跑过的路程同样是乙的两倍。
最后的等式k = mc + x,结合图示我们知道,若此时甲从A重新出发向着B前进,乙从D出发,沿着环路前进,速度相同,那么要么乙没用绕圈就与甲在B相遇,要么绕了几圈后与甲在B相遇,这取决于k与c的关系,若k远大于c那么乙就不的不在环路循环,以等待甲。
好了,这问题就明了了,为了找到环路的起始点,我们利用判断环路存在的方法来得到首次相遇的结点,然后调整两个指针的步长,使其相等,然后一个在相遇点继续走,一个回到出发点重新走,则二者再次相遇的位置就是环路的起始点。
//CODE
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head == NULL || head->next == NULL)
return NULL;
ListNode *pfast, *pslow;
pfast = pslow = head;
//
while(pfast && pfast->next)//notice condition
{
pfast = pfast->next->next;
pslow = pslow->next;
if(pfast == pslow) break;
}
if(pfast != pslow)
return NULL;
pfast = head;
//
while(pfast != pslow)
{
pfast = pfast->next;
pslow = pslow->next;
}
return pfast;
}
};