单链表判环的讨论

聊天时听到的这个问题,即有一个单链表,可能有环(见图),请判断出是否存在这个环?

貌似这是很常见的面试题(我居然没印象)。

单链表判环

最简单的思路

既然有个环,那就直接遍历一遍环呗,用个数组标记一下。时间复杂度和空间复杂度都是O(n)。

这个思路的问题就是在于空间复杂度是O(n),所以面试中,面试官总会再问,有没有更好的解决方法。然后我表示我只能想到这个。。。然后果断就悲剧了。

然后我就查到这个快慢指针法了。。。(看来看点面试题还是有必要的)

快慢指针法

说实话,这个方法以前见到过,但是还真没记住。看到这个问题时完全没印象,直到说一个走一步一个走两步时才隐约想起。(这果断就是被刷的节奏)

快慢指针法就是用两个指针(好心的面试官还是会提醒一下的),指针a一次走一步,指针b一次走两步如果有环,必然会在某个时间走到同一个点上,否则,B指针会先过末尾(可能长度为奇数)。

问题来了,为什么必然会相遇?

其实,一个走一步,一个走两步,很容易让人想起追及问题,当然不完全等同,追上和同时走到一个点不是同一个概念,后者是离散的。

但是当二者的步数差为1的时候,奇迹就发生了。如果链表有环,那么两个指针必然最后都会到环里。我们可以认为a始终在b的前面,同一方向嘛。b每次跳跃都会离a近一步,环又可以认为是无限远的,所以总会追到,在某个时刻两个指针位于同个节点。

再进一步

上面证明了如果有环它们必然会相遇,但是会在哪里相遇呢,如何找到那个入口点呢(面试官果断会这么问)。

单链表判环

设起点到入口(类似上图A->D)距离为x(步)。那个环的长度(类似上图D->J->D)为y(步)。a指针速度为1,b指针速度为2,时间设为t。

那么,如果两个指针走到同一个节点,就会有这么一个等式:(1*t-x)%y=(2*t-x)%y 这个应该很容易看懂,a指针和b指针走过的路程减去环外的那段,对环的长度取摸必然是相等的

简化一下那个等式,我们就会发现 t%y=0;于是就得到一个结论,只要时间t是环长度y的倍数,则两个指针走到同个节点。这时我们可以假设t=b*y,一个y的倍数。那么在环内的位置就是 (2*b*y-x)%y 。环的入口应该就是当(v*t-x)%y=0 的时候,v是速度(步伐数)。对比一下就能发现,只要从两个指针相遇点前进x步就能到达环入口

至此,问题已经解决,至于实现方面,x步可以存个变量,如果要求只能用两个指针,那就用其中一个指针从起点往入口点走,另一个指针从相遇点往前走,相遇之时就是到入口点之时

总结:

说实话,如果没听说过快慢指针这个算法,还真想不到。这个算法也有称为奇偶指针的,因为一个一步,一个两步。我觉得真正关键的点是在于两个指针的步伐差1

最后的用两个指针找入口点的走法,是把长度转换为了时间,度量除了x的长度。比较巧妙。

如果我一个走3步,一个走4步呢?还是能得出答案。关键点在于步伐差一。至于这样是不是更快呢?恐怕实际情况并不是二者步伐越长越好,因为虽说步伐数大了,进入环快了,但是在环中绕的圈数可能反而增加。所以没有必要加大步伐数。

转载请注明:旅途@KryptosX » 单链表判环的讨论

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值