单链表有关 环 的问题

说起关于单链表的环,无非以下几种常见问题  。
  1求单链表是否有环 。 
  2求单链表的入环点。   
  3求环的长度。

  对于 问题1,记得我第一次接触的时候,比较暴力,直接定义了个数组存放链表所有节点的地址。 遍历链表每读到下一个节点的时候,都要和已知结点的地址数组比较,看是否相同。这种解法的优点 仅仅是的确很好想,但时间复杂度 空间复杂度都很高。
   因此就要寻找更优的解法,我起初的那个很差且很low的解法可以扔了。
  
  新解法的突破口在哪里呢。
  想想单链表涉及的很多减少复杂度的做法都是定义快慢指针。

  比如 打印单链表中间节点的值,链表长度未知
  大部分人一开始是先遍历下链表,确认长度,然后长度取半,再遍历到一半的位置。
  其实 更优的做法是,定义快慢两个指针,两者同时遍历,快指针一下往后遍历2个结点,慢指针一下往后遍历1个结点,等到快指针到链表尾巴了,慢指针也走到中间了,打印慢指针所指结点信息就ok了。

  再比如 打印单链表倒数第k个的值,链表长度位置。
  大部分人一开始也是遍历链表确认长度,然后让 再遍历到  (长度-k)的位置打印。
  更优做法是,定义快慢指针,快指针先走k个结点,然后慢指针出发,快慢指针同时往后走,快指针到末尾时,慢指针就自然到了倒数k的位置。

 还有类似的问题。。。。
 因此我们能发现单链表和快慢指针有着莫大的关联!!

因此新解法就从这点作为启发出发,带环链表的特点是什么?小笨猪都知道是会从 入环点开始循环。
快慢指针?循环?   是否联想到追击相遇问题?

定义快指针每次走2个结点,慢指针走1个结点,如果链表没有环,慢指针一辈子也追不上快指针。
但是有环了就代表快指针到达目的地就会开始打转,慢指针追上快指针成为了可能。
因此判断是否有环函数非常简单。
快指针遇到NULL就代表有结尾,自然就没有环。
在快指针没遇到NULL的情况下,被慢指针追上了,就代表环的存在。

图示
红色快指针
蓝色慢指针
给了两个带环链表


   绿色圈起的结点为相遇点,这个点对于后两个问题来说非常重要!!!
   有人会担心一种情况,慢指针进入环区了,然后快指针再次进环,快指针增长大会再次超过慢指针,导致判断  (慢指针==快指针)被略过。其实并不会! 从快慢指针跳跃长度来想,快指针一下跳2次,慢指针一下跳一次,出现那种情况的前提是,上一步慢指针已经和快指针相等了,然后快指针才能跳过慢指针。但是如果上一步已经相等了,我们还能进入到这一步吗?显然不能的。

该求问题2 求单链表的入环点。   
还记得刚才的绿色圈起的相遇点吗
再定义一个指针从头节点触发,慢指针从相遇点出发,两个指针总会在入环点处碰面。
至于为什么这样做?它的原理是什么?那就是:记住就好了

  3求环的长度。
  其实和2问题有些像,那就是继问题1后,快慢指针从相遇点继续按照快指针2结点,慢指针1结点 走,快慢 再次相遇时,它们走过的结点数就是环的长度。


有时还会问道带环链表的总长度, 环长度+头节点到入环点长度就好,也就是问题2,3的结合。

测试一下。创建一个带环链表,0   1  2  3  4  5  6  7  8  9     入环点选7
   

如预期一样,789开始无限循环

判断是否有环


获取入环点


获取环长度


结果如下

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值