一道不错的算法题-判断链表是否有环
2011-08-25 20:04
330 查看
这是之前朋友出的一道题目,感觉不错,就拿来分享一下。
问题如下:
一个单向链表,怎么判断他是否存在环?
图示:
对于最简单的做法就是:
用一个指针走一圈,如果重复遇到其他任何一个指针,则证明有环。
但是这样做的问题就是:
单指针需要留下脚印,会弄脏链表数据,而如果不能脏数据的话,就需要增加一个容器,并且增加查找的开销。
有没有更好的方法呢?有的,定义一对快慢指针分别为ptr_fast,ptr_slow,ptr_slow走一步,ptr_fast走两步,如果ptr_slow和ptr_fast最终能相遇,那么证明有环。
解释如下:
画图:
设步长分别为x和y,链表回环结点数为n,非环回环为m
设经过t次跨步,则只要xt和yt对n同余并且xt和yt都大于m就可以相遇(假设x>y)
xt-yt=pn
yt>m
得到:
t=pn/(x-y) > m/y(只需pn可整除(x-y))
指针移动次数为(x+y)t=(x+y)/(x-y)*pn
而要想pn永远整除(x-y),那么x-y=1即可。在x-y固定为1的情况下x+y越小,则移动次数越少,也即指针比较次数越少,所以x为2,y为1。
其实还有第二个问题,即,假设ptr_fast在ptr_slow走完一圈前相遇,那环的长度和链表的长度分别为多少。(注意:以下方法是有问题的,如果ab足够长的话,那可能是在好几圈之后相遇的)
我们根据第一个问题的结论,假设ptr_fast和ptr_slow在c点相遇。
图示:
假设x是速度,t是时间。
则对ptr_slow:
ab+bc = x * t
对ptr_fast:
ab+bc+cb+bc = 2x*t
所以得出:
cb + bc = ab + bc
即:
cb = ab
所以环的长度就求出来了,即bc+cb = bc + ab = ptr_slow走的路程。
那链表的长度呢?
现在已经有了ab+bc的长度,只需要知道ab或者cb的长度即可:
再创建一个指针ptr_new,让ptr_new从head开始,和ptr_slow同时开始走,都是每次一步,由于ab == cb,所以他们相交的地方就是b点。所以即可得到整个链表的长度。
如果不是在慢指针走一圈内相遇,我还没有想到有算出环的长度和链表长度的方法,大家如果有答案欢迎告知~~
问题如下:
一个单向链表,怎么判断他是否存在环?
图示:
对于最简单的做法就是:
用一个指针走一圈,如果重复遇到其他任何一个指针,则证明有环。
但是这样做的问题就是:
单指针需要留下脚印,会弄脏链表数据,而如果不能脏数据的话,就需要增加一个容器,并且增加查找的开销。
有没有更好的方法呢?有的,定义一对快慢指针分别为ptr_fast,ptr_slow,ptr_slow走一步,ptr_fast走两步,如果ptr_slow和ptr_fast最终能相遇,那么证明有环。
解释如下:
画图:
设步长分别为x和y,链表回环结点数为n,非环回环为m
设经过t次跨步,则只要xt和yt对n同余并且xt和yt都大于m就可以相遇(假设x>y)
xt-yt=pn
yt>m
得到:
t=pn/(x-y) > m/y(只需pn可整除(x-y))
指针移动次数为(x+y)t=(x+y)/(x-y)*pn
而要想pn永远整除(x-y),那么x-y=1即可。在x-y固定为1的情况下x+y越小,则移动次数越少,也即指针比较次数越少,所以x为2,y为1。
其实还有第二个问题,即,假设ptr_fast在ptr_slow走完一圈前相遇,那环的长度和链表的长度分别为多少。(注意:以下方法是有问题的,如果ab足够长的话,那可能是在好几圈之后相遇的)
我们根据第一个问题的结论,假设ptr_fast和ptr_slow在c点相遇。
图示:
假设x是速度,t是时间。
则对ptr_slow:
ab+bc = x * t
对ptr_fast:
ab+bc+cb+bc = 2x*t
所以得出:
cb + bc = ab + bc
即:
cb = ab
所以环的长度就求出来了,即bc+cb = bc + ab = ptr_slow走的路程。
那链表的长度呢?
现在已经有了ab+bc的长度,只需要知道ab或者cb的长度即可:
再创建一个指针ptr_new,让ptr_new从head开始,和ptr_slow同时开始走,都是每次一步,由于ab == cb,所以他们相交的地方就是b点。所以即可得到整个链表的长度。
如果不是在慢指针走一圈内相遇,我还没有想到有算出环的长度和链表长度的方法,大家如果有答案欢迎告知~~
相关文章推荐
- 判断一个链表是否回文(每日一道算法题)
- 算法习题8:判断俩个链表是否相交
- 算法:判断一个链表中是否有环
- 算法-微软亚院之编程判断俩个链表是否相交
- 每天学习一算法系列(8) (编程判断俩个链表是否相交)
- 【算法之链表(一)】判断单链表中是否有环、环的长度、环的入口节点,单链表的倒数第K个节点等
- java小算法—判断单链表中是否有环(链表头尾不相连)
- 判断一个单向链表是否有环,算法证明
- 算法面试100题——7.微软亚院之编程判断俩个链表是否相交
- 笔试算法题(25):复制拥有多个指针的链表 & 判断二元树B是否为A的子树
- 百度笔试算法第二题:如何判断两个单向链表是否有相交,并找出交点
- 算法-单链表-判断链表是否有环,是否交叉,计算环长,计算入环节点
- 算法题006 判断两个链表是否相交
- [算法]判断一个链表是否有环
- 算法题 1 判断两条单链表是否交叉 一百度实习笔试题(2012.5.6)
- 设单链表中存放n个字符,试设计一个算法,使用栈判断该字符串是否中心对称
- 每天一道算法题(5)——判断整数序列是否是二叉查找树后序遍历结果
- [算法练习FindLoop]判断单向链表是否存在循环/循环入口/环长度
- 经典算法 | 判断任意长度链表是否有环的O(n)时间,O(1)空间算法
- 笔试算法题(27):判断单向链表是否有环并找出环入口节点 & 判断两棵二元树是否相等