问题:
如何判断一个链表是否有闭环?
今天看到了这个问题,提到了Floyd判圈算法,于是去查了一下这个算法,把自己的一点想法写下来。
问题的答案是:
从链表的头部设置两个指针,p1的步长为1, p2的步长为2,同时向前走,如果p1和p2最终能够相遇,则说明链表是有环的。
检测环的基本思想是非常简单的,可以类比成两个人在跑道上跑。只要有圈,跑的快的那个人就一定能够追上跑得慢的那个人。
另外,还有两个相关的问题,一个是如何求环的长度,另一个是如何求环的起点。
求环的长度
这个也能非常简单的想到:
两个人相遇的是时候,一定已经在环上了,然后两个人只要再次在环上接着跑,再次相遇的时候(也就是所谓的套圈),跑的快的那个人就比跑得慢的人整整多跑了一圈,所以环的长度也就出来了。
用算法来描述,也就是第一次相遇后,p1和p2按照原来的步长继续向前查找,并且记录下两个指针遍历过的节点个数。当两个指针再次相遇的时候,遍历的节点数量差就是环的长度了。
第二个就是求环的起点
解决方法是把其中的一个指针重置到链表头部,然后两个指针步长都为1,继续向前移动,相遇的位置即为环的起点。
方法的解析如下:
首先我们设第一次相遇的时候慢指针走过的节点个数为i,设链表头部到环的起点的长度为m, 环的长度为n,相遇的位置与起点位置距离为k。
则可以得到:
i = m + a * n + k
其中a为慢指针走的圈数。
根据快指针和慢指针的速度关系,我们可以得到另一个式子:
2 * i = m + b * n + k
其中b为快指针走的圈数。
简单处理得到:
i = (b - a) * n
也就是说i是圈长的整数倍。
这时将其中一个节点放到起点,然后同时向前走m步时,此时从头部走的指针在m位置。而从相遇位置开始走的指针应该在距离起点i + m
, i为圈长整数倍,则该指针也应该在距离起点为m的位置,即环的起点。