剑指 Offer II 022. 链表中环的入口节点

这篇博客介绍了如何利用双指针法解决链表环的问题。首先,通过一个简单的遍历方法,利用HashSet检查节点是否存在环。其次,采用快慢指针策略,快指针每次前进两步,慢指针前进一步,当两者相遇时确定存在环,并从起点开始的慢指针与相遇点同时前进,直至再次相遇,这个点即为环的入口节点。
摘要由CSDN通过智能技术生成

概要

双指针法,很快~

题目

给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next 指针进入环的第一个节点为环的入口节点。如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

说明:不允许修改给定的链表。

img

链接:https://leetcode.cn/problems/c32eOV

思路

将链表从头开始遍历,并将每个节点保存到HashSet中。遍历过程中判断当前节点是否出现过。如果出现了,则该节点就是我们要返回的节点。

解法一:遍历链表,并判断当前节点是否出现过

代码

public ListNode detectCycle(ListNode head) {
    Set<ListNode> nodes = new HashSet<>();
    ListNode dummy = new ListNode();
    dummy.next = head;
    while (dummy.next != null) {
        if (nodes.contains(dummy.next)) {
            return dummy.next;
        } else {
            nodes.add(dummy.next);
        }
        dummy = dummy.next;
    }
    return null;
}

解法二:双指针定位+双指针移动

逻辑

题目中也提到了能否用O(1)的空间复杂度来解决问题。确实,上一题的解法,简单粗暴但并不占优。

那么我们可以继续祭出双指针法。这次双指针是不一样的,分为快慢指针。快指针一次走两步,慢指针一次走一步。如果存在环,则快指针总会把慢指针套圈。在相遇时,快指针走的路程是慢指针的两倍。我们画一个图来看:

img

A是起点,B是环的入口节点,C是两个指针汇合点。我们记录AB之间的距离是a,B到C之间顺时针的距离是b,C到B之间逆时针的距离是c。

那么我们可以得到这样的公式:2(a+b)=a+b+c+b。最终可得a=c

所以,当两个指针碰面后,再用一个新的慢指针从起点出发,与旧的慢指针一同前行,知道两个指针相遇,则相遇的节点就是B点。

代码

public ListNode detectCycle(ListNode head) {
    ListNode dummy = new ListNode();
    dummy.next = head;
    ListNode fast = dummy;
    ListNode slow = dummy;
    ListNode newSlow = dummy;
    while (fast.next != null && fast.next.next != null) {
        fast = fast.next.next;
        slow = slow.next;
        if (fast.equals(slow)) {
            // 新的慢指针出发
            while (newSlow != slow) {
                newSlow = newSlow.next;
                slow = slow.next;
            }
            return slow;
        }
    }
    return null;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小白码上飞

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

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

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

打赏作者

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

抵扣说明:

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

余额充值