leetcode
leetcode 2551 ~ 2600
环路检测

环路检测

难度:

标签:

题目描述

Given a circular linked list, implement an algorithm that returns the node at the beginning of the loop.

Circular linked list: A (corrupt) linked list in which a node's next pointer points to an earlier node, so as to make a loop in the linked list.

Example 1:

Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1

Example 2:

Input: head = [1,2], pos = 0
Output: tail connects to node index 0

Example 3:

Input: head = [1], pos = -1
Output: no cycle

Follow Up:
Can you solve it without using additional space?

代码结果

运行时间: 60 ms, 内存: 17.9 MB


/*
 * Java Stream API 不能直接处理链表问题,尤其是涉及到环检测。
 * 但是可以通过构建辅助方法来实现相似的功能。
 * 以下是使用 Java 代码来模拟 Stream 风格的链表环检测方法。
 */
public class Solution {
    class ListNode {
        int val;
        ListNode next;
        ListNode(int x) {
            val = x;
            next = null;
        }
    }
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) return null;
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                slow = head;
                while (slow != fast) {
                    slow = slow.next;
                    fast = fast.next;
                }
                return slow;
            }
        }
        return null;
    }
}

解释

方法:

这个题解使用了快慢指针的方法来检测链表中是否存在环,并找到环的入口。首先,设置两个指针s(慢指针)和f(快指针),它们都从头节点开始。慢指针每次移动一步,快指针每次移动两步。如果链表中存在环,那么快慢指针最终会在环内相遇。在快慢指针相遇后,将快指针重新指向头节点,然后快慢指针都每次移动一步,直到它们再次相遇的位置,这个位置就是环的入口。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在快慢指针相遇后,将快指针重新指向头节点并以相同速度移动,它们再次相遇的位置就是环的入口?
当快慢指针在环中首次相遇时,可以推断出快指针比慢指针多走了环的长度的整数倍。假设从头节点到环入口的距离为D,环的周长为C,并且当快慢指针首次相遇时慢指针已经在环中走了K步(K可能小于C)。在首次相遇点,快指针走的步数为D + nC + K(n为快指针绕环的圈数),且快指针走的步数是慢指针的两倍,即2(D + K)。通过这些等式,我们可以推导出D = (n-1)C + (C-K)。这意味着从链表头到环入口的距离等于从相遇点绕环走回到入口的距离。因此,当你将快指针重置到头节点后,它们以相同的速度移动,最终会在环的入口相遇。
🦆
如果链表的长度非常大,快指针移动两步是否可能导致跳过环的入口?
不会。快指针每次移动两步并不会导致跳过环的入口。无论链表有多长或环的大小如何,快指针移动的步数始终是连续的,并且每次只跳过一个节点。因此,即使链表非常大或环很小,快指针也不可能跳过环的入口。
🦆
在快慢指针的方法中,如何保证当快慢指针再次相遇时,它们的位置一定是环的入口,而不是环中的其他位置?
这是基于数学推导得出的结论。首次相遇后,我们知道从链表头到环入口的距离与从相遇点绕环回到入口的距离相等。因此,当我们将一个指针重置到链表头部,另一个指针保留在首次相遇点,然后让它们以相同的速度移动时,它们会在环入口相遇。这是因为它们同时开始向环入口移动,并且以相同的速度行进,所以它们必须同时到达环入口。
🦆
如果链表中的环非常小,例如只包含两个节点,这个算法的逻辑是否还适用?
是的,这个算法仍然适用,无论环的大小。算法的核心在于快慢指针的相遇点和数学推导,说明从链表头到环入口的距离等于从相遇点绕环到达入口的距离。因此,无论环有多大或多小,只要存在环,该算法都能正确地找到环的入口。

相关问题