问题:如何检测一个链表是否有环(循环节),如果有,那么如何确定环的起点以及环的长度。
空间要求:不能存储所经过的的每一个点。
举例:
x0=1
x
0
=
1
,
xi+1=f(xi)
x
i
+
1
=
f
(
x
i
)
,求循环节的起始位置以及循环节的长度。
求解步骤:
1.判断是否有环
使用两个指针slow和fast。两个指针开始时均在头节点处(
S
S
点),slow指针(龟)一次向后移动一个一步,fast指针(兔)一次向后移动两步。若存在环,则slow和fast必能相遇;反之若slow到达链表尾时两个指针仍不能相遇,则不存在环。
证明
设头节点S与循环节起始点
A
A
之间举例|SA|=m。两个指针在
B
B
点相遇,|AB|=n。可知环中的点满足
xi=xi+kl
x
i
=
x
i
+
k
l
,其中
l
l
为循环节的长度,也就是说fast比slow多走了整数圈。当i=kl时,满足
xi=x2i
x
i
=
x
2
i
,这样的
i
i
一定存在,得证。
2.计算环的长度
这一步比较简单,让其中一个指针停在B不动,另一个一步一步向前走并记录步数,再次相遇时步数即为环的长度。
3.寻找环的起点
其中一个指针在
B
B
不动,另一个放到起点S,两个指针同时一步一步移动,则两指针将会在循环节的起点相遇。
证明
B
B
点的下标 i=kl为
l
l
的整数倍。当放到S处的指针移动
m
m
到达A时,放在
B
B
的指针移动到i+m=kl+m处,于是两个指针相遇。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 2e7;
int f(int x)
{
int res = 0;
return res;
}
bool FloydCycle(int ori, int &len, int &id, int &val)
{
int slow, fast;
slow = f(ori);
fast = f(f(ori));
int cnt = 1;
while(slow != fast && cnt <= maxn)
{
slow = f(slow);
fast = f(f(fast));
cnt++;
}
if(slow != fast) return false;
len = 1;
slow = f(slow);
while(slow != fast)
{
slow = f(slow);
len++;
}
id = 0;
slow = 1;
while(slow != fast)
{
slow = f(slow);
fast = f(fast);
id++;
}
val = slow;
return true;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)