环形链表力扣--142

本文介绍了如何利用快慢指针的方法解决链表环的问题,通过定义快指针每次走两个节点,慢指针走一个节点,一旦相遇即说明存在环。进一步分析环的入口,通过设置两个指针从头和相遇点同时开始单步移动,它们的相遇点即为环的入口。
摘要由CSDN通过智能技术生成

目录

题目

思路

代码


题目

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

思路

题目有两个要求:1.判断是否有环  2.如果有,找到环的入口

首先来看第一个要求

定义一个快指针一个慢指针,让快指针一次走两个结点,慢指针一次走一个结点,如果有环的话快指针会先进入,然后满指针也进入,快指针走的快,一直在环里,所以一定会和慢指针相遇,所以这个可以用来判断是否有环。

Q:为什么快指针要走两个节点? 

A:快指针走两个,慢指针走一个,所以快指针相当于慢指针只走了一个,相当于快指针一格一格逼近慢指针,假如快指针一下走三个的话很有可能就直接跳过慢指针了。

然后我们来看第二个要求

 假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。

那么相遇时: slow指针走过的节点数为: x + y, fast指针走过的节点数:x + y + n (y + z),n为fast指针在环内走了n圈才遇到slow指针, (y+z)为 一圈内节点的个数A。

Q:为什么慢指针这里不用再加一个k(z+y)?也就是说为什么慢指针一定在第一圈的时候就被快指针追上去了?

A:把环展开

相当于在这个中间慢指针一定会被快指针相遇

因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2:

(x + y) * 2 = x + y + n (y + z)

两边消掉一个(x+y): x + y = n (y + z)

因为要找环形的入口,那么要求的是x,因为x表示 头结点到 环形入口节点的的距离。

所以要求x ,将x单独放在左面:x = n (y + z) - y ,

再从n(y+z)中提出一个 (y+z)来,整理公式之后为如下公式:x = (n - 1) (y + z) + z 注意这里n一定是大于等于1的,因为 fast指针至少要多走一圈才能相遇slow指针。

特殊情况:当n=1的时候,我们得到x=z

所以我们在相遇的点处设置一个l1,在头的部分设置l2 ,让他们移动相同距离,最终他们相遇的位置就是环的入口

从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点

Q:那n大于1是什么情况?

A:相当于快指针在环中绕了n-1圈以后然后才和l2相遇,看图即可理解

代码

public class Solution {
    public ListNode detectCycle(ListNode head) {
         ListNode fast=head;
         ListNode slow=head;
         while(fast!=null&&fast.next!=null){//因为快指针要一次跳两格,所以要确定它和它的下一个都不能为null
            fast=fast.next.next;//fast跳两格
            slow=slow.next;//slow跳一格
            if(slow==fast){//相遇了,判断有环了
                ListNode l1=fast;
                ListNode l2=head;
            while(l1!=l2){//他俩还没相遇,继续遍历
                l1=l1.next;
                l2=l2.next;
            }
            return l1;//找到返回
         }
         }
         return null;//没有环
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值