leetcode习题287 Find the Duplicate Number 在答案中看到了floyd’s tortoise and hare 算法,知道了如果有限状态机、迭代函数或者链表存在环,那么是需要算法检测环是否存在。检测算法有三种:Floyd龟兔算法、Brent算法、Gosper算法。
Floyd龟兔算法
算法描述
Floyd龟兔算法是一种指针算法。该算法仅使用移动速度不同的两个指针就能检测出是否有环。Floyd龟兔算法解决以下问题:1检测是否有环。2环的起点节点。3环的长度。
1 检测是否有环。
想象在一个环形跑道上跑步,两个人同时出发,出发以后速度快的人终究会在某一点和速度慢的人相遇。一般这个时候相遇,速度快的人比速度慢的人至少多跑一圈。
我们假设列表的开始节点是S,环上的起始节点是P,第一次相遇的节点是M。S和P的距离是p,从P和M的距离是m,从M到p的距离是n。指针t和h初始状态下都指向S。接着t每次只有1步,h每次走2步。只要二者没有相遇,就一直按着这个速度走下去。当h无法前进(到达队列末尾)的时候,可以判断没有环。如果t和h在某点再次相遇,则确定有环。
举一个迭代函数的例子。有函数f定义域和值域都是 S = {0,1,2,3,4,5,6,7,8},从x0=2x_0=2x0=2开始,不断重复调用f,能够产生一个序列:2,0,6,3,1,6,3,1,6,3,1…产生了一个环:6,3,1。
定义:S是一个有限集合,f是一个函数,从S到S的一个映射,x0x_0x0可以是S中的任意一个元素。对于任意的i>0i>0i>0,xi=f(xi−1)x_i=f(x_{i-1})xi=f(xi−1)。μ\muμ是换上的起点节点的最小下标,λ\lambdaλ是环的长度。一定有xμ=xλ+μx_\mu=x_{\lambda+\mu}xμ=xλ+μ
证明:如果有环存在,则对于任意的整数i>=μi>=\mui>=μ并且k>0k>0k>0,都有xi=xi+kλx_i=x_{i+k\lambda}xi=xi+kλ。对于特定的k来讲,一定存在使得i=kλi=k\lambdai=kλ,那这时候xi=x2ix_i=x_{2i}xi=x2i。至此,说明了速度不同的两个指针可以在某点相遇。
2 计算环长度
当t和h相遇在M点。因为相遇的点一定在环上。这时候保存h不动,t按之前的速度继续前进,直到和h再次相遇,这个过程中移动的步数就是环的长度。
3 环的起始节点确定
在确定是否有环的过程中,h走的距离是t走的距离的2倍。c为环长。t走的距离是 s1=p+m+a∗cs1=p+m+a*cs1=p+m+a∗c,h走的距离是2∗s1=p+m+b∗c2*s1=p+m+b*c2∗s1=p+m+b∗c,两式子相减得到:s1=(b−a)∗c=p+m+a∗cs1=(b-a)*c=p+m+a*cs1=(b−a)∗c=p+m+a∗c,得到p+m=环的整数倍。
为了找到环的起点,t回到起点,h在当前位置。同时向前,他们再次相遇一定在P点。为什么呢?因为从S到P的距离是p,从P到M的距离是m,因为m+p是环长的整数倍,所以当h走过距离p的时候也一定达到了P点。
算法时间复杂度:令S到P的距离为m,环的长度为n,时间复杂度O(m+n)O(m+n)O(m+n)。
空间复杂度:O(1)。
参考
网页1
网页2
网页3