算法数据结构---环形链表

本篇主要是在学习链表数据结构中时,操作环形链表时所一步一步执行的操作。

题目来源于力扣142.环形链表Ⅱ

此题在考察链表的基础操作下,还主要考查了两个知识点:

(1)判断链表是否有环

(2)如果有环,如何找到该环的入口

首先我们回答问题(1):如何判断链表是否存在环?

回顾我们之前的单链表,假设我们定义了双指针(快慢指针),如果链表没有环,那么由于fast指针(快指针)走得,一旦超过slow指针(慢指针)那么slow指针之后将不再有机会和fast指针相遇,这是毋庸置疑的,因为是一直沿着直线走下去的。

请添加图片描述

那么如果链表有环呢?slow指针是不是也永远不可能再和fast指针相遇呢?答案是一定会相遇。我们可以这样定义fast和slow指针,其中fast指针每次移动两个节点slow指针每次移动一个节点,如果这样fast和slow在途中相遇,说明这个链表有环

下面解释为什么这样定义,以及这样定义为什么一定会让fast和slow指针在环内相遇:

fast指针每次走两节点,slow指针每次走一节点,那么相当于是fast指针再以2-1=1节点的速度追赶slow指针,1节点的速度追赶相当于是单步单步接近slow指针的,所以一定会在某个时刻slow指针相遇。如果我们这里定义fast每次走三节点,那么就不一定会相遇了,因为此时fast以两节点的速度追赶slow,由于不是单步单步去逼近slow,所以有可能直接跳过slow

对于问题(2):如果链表有环,怎样才能找到环的入口呢?

我们可以先假设头节点到环形入口节点的节点数为x环形入口节点到fast指针与slow指针相遇节点的节点数为y;从相遇节点再到环形入口节点的节点数为z。如下图:

请添加图片描述

则相遇时:
slow指针走过节点数: x+y
fast指针走过节点数: x+y+n(y+z)

这里的n相当于是fast指针环内走了n圈才与slow指针相遇

由于fast指针一次走2节点,slow一次走1节点,那么fast指针走过节点数=2*slow指针走过节点数
由此:
2(x+y)=x+y+n(y+z)

化简一下得到:
x=(n-1)(y+z)+z

这里n一定是大于等于1的,因为fast至少多走一圈才能与slow相遇

通过化简后的公式,我们可以分析出:

n=1时,x=z,说明fast指针在环内走了一圈后就与slow指针相遇了;同时,由于x=z,说明从头节点出发一个指针index1,从相遇节点也出发一个指针index2,两指针每次只走1个节点,那么当这两个指针相遇时也就找到了环形入口的节点

n>1时,x=(n-1)(y+z)+z,我们仍然可以这样定义两个指针,只不过此时的index2指针环内多走了n-1圈后才与index1指针入口节点处相遇

由此便可编写代码:

public class Solution {
    public ListNode detectCycle(ListNode head) {
    
    	//定义快慢指针
        ListNode slow = head;
        ListNode fast = head;
        
        //由于fast指针走得快,仅对其条件判断即可
        //由于fast指针一次走2个节点,在判断当前节点不为空的条件下,还要判断下一节点不为空
        while (fast != null && fast.next != null) {
        	//慢指针1次走1个节点
            slow = slow.next;
            //快指针1次走2个节点
            fast = fast.next.next;
            if (slow == fast) {// 说明有环,且快慢指针相遇点为slow/fast
            
            	//定义一个从相遇点出发的指针index1
                ListNode index1 = fast;
                
                //定义一个从头节点出发的指针index2
                ListNode index2 = head;
                
                // 两个指针,从头结点和相遇结点,同时开始走,一次走一步,直到相遇,相遇点即为环入口
                while (index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                //跳出while循环后说明index1=index2,此时相遇,说明环入口即为index1/index2
                return index1;
            }
        }
        //链表无环,返回null
        return null;
    }
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丷江南南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值