判断是否存在环

定义两个指针 p1,p2,从head节点开始遍历,每次循环p1向前移一位,p2向前移两位,若链表存在环则p1,p2必然有相等的时候。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function hasCycle($linkedList)
{
 	$p1 = $p2 = $linkedList->headNode;
 	while ($p1->nextNode) {
        $p1 = $p1->nextNode;
        $p2 = $p2->nextNode->nextNode;
        if ($p1 == $p2) {
            return true;
        }
 	}

 	return false;
}

找出环的位置

假设 p1 经过的路程是 S,因为 p2 速度是 p1 的 2 倍,所以 p2 经过的路程为2S

假设 p2 比 p1 多走n圈的距离才到达汇合点,那么可以得出:

$2S = S + NR$ 即$S=NR$

代入 $2S = A+ X + NR$

得出 $NR = A + X$

又 $R=X+T$

代入得

$NR=A+R-T$$ 即 $$A=(N-1)R+T$

根据上述推导的公式可以得出结论:从汇合点和起点的两个指针定会在环的交点相遇!

代码来了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
function getCycleNode($linkedList)
{
 	$p1 = $p2 = $linkedList->headNode;
 	while($p1->nextNode) {
        $p1 = $p1->nextNode;
        $p2 = $p2->nextNode->nextNode;
        if ($p1 == $p2) {
            break;
        }
 	}
    
    if (!$p1) {
        return false;
    }
    $p3 = $linkedList->headNode;
    while($p1 != $p3) {
        $p1 = $p1->nextNode;
        $p3 = $p3->nextNode;
    }
    
    return p1;
}