环形链表 II - LeetCode 热题 26

本文介绍了解决LeetCode环形链表问题的算法,利用快慢指针在链表中找到环的入口节点,通过控制指针速度和相遇点来确定环的结构。
摘要由CSDN通过智能技术生成

大家好!我是曾续缘😛

今天是《LeetCode 热题 100》系列

发车第 26 天

链表第 5 题

❤️点赞 👍 收藏 ⭐再看,养成习惯

环形链表 II

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

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

不允许修改 链表。

    示例 1:

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

    示例 2:

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

    示例 3:

    输入:head = [1], pos = -1
    输出:返回 null
    解释:链表中没有环。
    

    提示:

    • 链表中节点的数目范围在范围 [0, 104]
    • -105 <= Node.val <= 105
    • pos 的值为 -1 或者链表中的一个有效索引

    进阶:你是否可以使用 O(1) 空间解决此题?

    难度:💖💖

    解题方法

    寻找链表中环的入口节点

    这道题需要找到链表中环的入口节点,我们同样可以使用快慢指针的算法来解决。

    假设从链表头部到环的入口有 a a a 个节点,环中有 b b b 个节点。一个指针要走到入口处,其走过的步数 k k k 满足 k = a + n × b k = a + n \times b k=a+n×b 的数学关系。这意味着要么直接走 a a a 步到达入口,要么先走到入口然后绕环 n n n 圈回到入口。

    通过快慢指针可以检测链表是否存在环。当快慢指针相遇时,假设快指针走过的步数为 f f f,慢指针走过的步数为 s s s,则有以下关系:

    1. 快指针速度是慢指针的两倍,即 f = 2 × s f = 2 \times s f=2×s
    2. 快慢指针在环内相遇,快指针比慢指针多走了 n n n 圈,因此 f = s + n × b f = s + n \times b f=s+n×b

    通过上述方程组,我们得到重要的信息: s = n × b s = n \times b s=n×b,这意味着什么呢?

    当快慢指针相遇时,慢指针走过的步数是环节点数的整数倍!

    为了使慢指针到达环的入口,即满足 k = a + n × b k = a + n \times b k=a+n×b,只需让慢指针再走 a a a 步即可,或者继续多走几圈再返回。

    然而, a a a 是未知数,我们并不知道具体需要走多少步,该怎么办呢?

    a a a 表示链表头部到链表入口的节点数,我们可以将快指针置于链表头部,与慢指针速度相同。当它们再次相遇时,它们之间的距离差就是链表头部到链表入口的节点数,因此我们也就获得了 a a a,慢指针正好满足入口公式的条件。

    过程如下:

    1. 首先设定两个指针 slow 和 fast,初始化它们都指向头节点。
    2. 使用一个 do…while 循环,循环内部判断快指针和快指针的下一个节点是否为空,如果有一个为空,则说明链表无环,直接返回 null。
    3. 在循环内部,快指针每次向前移动两步,慢指针每次向前移动一步,直到它们相遇。
    4. 当快指针和慢指针相遇时,将快指针重新指向头节点,并将快指针和慢指针都以每次一步的速度向前移动。
    5. 当快指针和慢指针再次相遇时,相遇的节点即为环的入口节点。

    Code

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    public class Solution {
        public ListNode detectCycle(ListNode head) {
            if (head == null) {
                return null;
            }
            ListNode slow = head, fast = head;
            do {
                if (fast == null || fast.next == null) {
                    return null;
                }
                fast = fast.next.next;
                slow = slow.next;
            } while (fast != slow);
            fast = head;
            while (fast != slow) {
                fast = fast.next;
                slow = slow.next;
            }
            return fast;
        }
    }
    
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值