问题
如何检测一个链表是否有环?如果有环,如何确定环的起点以及长度?
Floyd cycle detection(龟兔算法)
龟兔赛跑
对于赛道来说,如果赛道中有环,那么速度快的兔子一定会在某个地点追上乌龟,并且兔子所跑的距离减去乌龟所跑的距离,一定是环长度的整数倍。
原理
假设令龟、兔为指针,并且指向起点位置,兔子每次移动两个节点,乌龟每次移动一个节点。如果两者在起始节点外相遇,则说明有环。如果兔子在走到链表尾部还没有与乌龟相遇,说明无环。
环长度
通过上述算法判断出存在环C时,显然龟兔位于同一节点M,此时,令兔子保持不动,而乌龟不断推进,记录移动距离,等再次相遇时,移动步数即环C长度。
环起点
只要令兔子仍位于相遇节点M, 而令乌龟返回链表起始节点S,此时乌龟与兔子之间的距离为环C长度的整数倍。随后,同时让乌龟与兔子不断推进一步,直至相遇同一节点P,则节点P即为从链表起始节点所到达的环C的第一个节点,即环C起点。
分析
如图所示,令起始节点为h
, 起始节点到环起点距离为m
, 龟兔相遇节点为p
, p
节点与环起点距离为n
;
当龟兔相遇时
乌龟所跑距离为 S = m + n + aC
(C 为环长度),
兔子所跑距离为2S = m + n + bC
(因为兔子速度为乌龟2
倍)
故得S = (b - a)C = m + n + aC ==> (b - 2a)C = m + n
, 由此可知,m + n
为环C
长度整数倍.
那么令乌龟返回链表起始节点,兔子仍在相遇节点P,两者同时不断推进直至相遇,相遇节点为环起点。因为乌龟移动距离m
, 则兔子也移动距离m
, 原本p
节点距离环起点为n
, 由于m + n
为环长整数倍,故兔子移动到了环起点,即相遇节点为环起点。