此问题分为两问:
- 对于某个单向链表,如何判断其有环
- 对于有环单向链表,如何获取首个环节点
第一问题解:
对于问题1,如何判断单向链表有环?一个高效的解决方法是:从链表头节点开始,设置两个指针,Fast与Slow这两个指针分别以一倍速(每次走一个节点)与二倍速(每次走两个节点)进行链表遍历。这样如果链表有环,当二者进入链表环内后,类比圆形跑道,跑的速度快的人可以套速度慢的人一圈,即两个指针一定会指向同一地址。这里可以证明:对于Fast与Slow这两个指针,如果二者差一步,则会在下一步赶上;如果二者差两步,则会在两步后赶上;其他情况最终会回到差一步与差两步的情况。
由此,只需进行移动,并每次移动后比较二者的地址是否相同,就可以判断链表是否有环了。
注:对于此问题,可以在第二问证明,Fast指针会在Slow指针未走完第一个循环时赶上,则此算法的时间复杂度为O(N),且无需申请额外的内存空间。
第二问题解:
这里需要配合图来进行说明:
如图所示,假设二者相遇时分别走了T个步长与2T个步长,可知首次追上时二者差X2个步长:
2
T
−
T
=
T
=
X
2
2T-T=T=X2
2T−T=T=X2
可知T=X2,又已知T个步长中包括X1个步长(X1>0),则可证slow指针未走完一个圆弧X2,其在圆弧中走X2-X1,此时距离环点还差
X
2
−
(
X
2
−
X
1
)
=
X
1
X2-(X2-X1)=X1
X2−(X2−X1)=X1,又知由H1至环点距离为X1,则有解:由头节点与交点各走一个指针,二者每次移动一个步长,比较地址,地址相同处即为环点。算法时间复杂度为O(N),不占用额外空间。