環形連結串列II

zhengbiyu發表於2024-07-07

給定一個連結串列的頭節點 head ,返回連結串列開始入環的第一個節點。 如果連結串列無環,則返回 null

如果連結串列中有某個節點,可以透過連續跟蹤 next 指標再次到達,則連結串列中存在環。 為了表示給定連結串列中的環,評測系統內部使用整數 pos 來表示連結串列尾連線到連結串列中的位置(索引從 0 開始)。如果 pos-1,則在該連結串列中沒有環。注意:pos 不作為引數進行傳遞,僅僅是為了標識連結串列的實際情況。

不允許修改 連結串列。

示例 1:

環形連結串列II

輸入:head = [3,2,0,-4], pos = 1
輸出:返回索引為 1 的連結串列節點
解釋:連結串列中有一個環,其尾部連線到第二個節點。

示例 2:

輸入:head = [1,2], pos = 0
輸出:返回索引為 0 的連結串列節點
解釋:連結串列中有一個環,其尾部連線到第一個節點。

示例 3:

輸入:head = [1], pos = -1
輸出:返回 null
解釋:連結串列中沒有環。

我們使用兩個指標, fast與 slow。它們起始都位於連結串列的頭部。隨後,slow 指標每次向後移動一個位置,而fast 指標向後移動兩個位置。如果連結串列中存在環,則 fast指標最終將再次與 slow指標在環中相遇。 如下圖所示,設連結串列中環外部分的長度為a。 slow指標進入環後,又走了b 的距離與 fast相遇。此時,fast指標已經走完了環的n 圈,因此它走過的總距離為a+n(b+c)+b=a+(n+1)b+nc。

根據題意,任意時刻,fast 指標走過的距離都為slow 指標的2倍。因此,我們有a+(n+1)b+nc=2(a+b)⟹a=c+(n−1)(b+c) 有了 a=c+(n−1)(b+c) 的等量關係,我們會發現:從相遇點到入環點的距離加上n−1 圈的環長,恰好等於從連結串列頭部到入環點的距離。 因此,當發現slow與fast相遇時,我們再額外使用一個指標ptr。起始,它指向連結串列頭部;隨後,它和slow 每次向後移動一個位置。最終,它們會在入環點相遇。

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode slow = head, fast = head;
        while (fast != null) {
            slow = slow.next;
            if (fast.next != null) {
                fast = fast.next.next;
            } else {
                return null;
            }
            if (fast == slow) {
                ListNode ptr = head;
                while (ptr != slow) {
                    ptr = ptr.next;
                    slow = slow.next;
                }
                return ptr;
            }
        }
        return null;
    }
}

時間複雜度:O(N),其中 N 為連結串列中節點的數目。在最初判斷快慢指標是否相遇時,slow 指標走過的距離不會超過連結串列的總長度;隨後尋找入環點時,走過的距離也不會超過連結串列的總長度。因此,總的執行時間為O(N)+O(N)=O(N)。

空間複雜度:O(1)。我們只使用了 slow , fast , ptr三個指標。

相關文章