141. 環形連結串列

Heinrich♣發表於2024-06-02
141. 環形連結串列
簡單
相關標籤
相關企業

給你一個連結串列的頭節點 head ,判斷連結串列中是否有環。

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

如果連結串列中存在環 ,則返回 true 。 否則,返回 false

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 連結串列中節點的數目範圍是 [0, 104]
  • -105 <= Node.val <= 105
  • pos-1 或者連結串列中的一個 有效索引 。

進階:你能用 O(1)(即,常量)記憶體解決此問題嗎?

思路

快慢指標,倆指標從頭節點出發,一個快指標每次走兩步,一個慢指標每次走一步,如果連結串列存在環路,那麼快指標會追上慢指標

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null || head.next == null || head.next.next == null) return false;
        ListNode slow = head, fast = head;
        while(fast != null && fast.next!=null){
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast) return true;
        }
        return false;
    }
}

證明快慢指標演算法(也被稱為弗洛伊德的龜兔賽跑演算法)的正確性,可以透過數學歸納法來完成。下面是證明的邏輯:

  1. 定義:假設連結串列由非環部分和環部分組成。設非環部分的長度為 𝑎a 個節點,環的長度為 𝑏b 個節點。

  2. 快指標進入環:當快指標(fast)進入環時,慢指標(slow)可能還在非環部分,或者已經在環內。

  3. 快慢指標相遇:當快指標在環內移動時,慢指標也在環內移動,但由於快指標的速度是慢指標的兩倍,它們最終會在環內的某個點相遇。

  4. 證明相遇:假設在快指標進入環之前,快慢指標已經移動了 𝑘k 步(𝑘<𝑎k<a)。此時,快指標開始在環內移動,而慢指標繼續在非環部分移動直到它也進入環。當慢指標進入環時,快指標已經在環內移動了 𝑘k 步。

  5. 環內相遇:在環內,快指標每走 𝑏b 步就會回到起點,而慢指標需要走 2𝑏2b 步。因此,每當快指標繞環一週,慢指標只繞了半周。這意味著,每過 𝑏b 步,快指標就會相對於慢指標多走 𝑏b 步。由於快指標和慢指標之間的初始距離是 𝑘k 步,經過 𝑘𝑏bk 輪之後,快指標將追上慢指標。

  6. 特殊情況:如果連結串列只有一個節點,或者沒有節點,快慢指標會在第一步就相遇,這符合我們的預期。

  7. 沒有環的情況:如果連結串列中沒有環,快指標會在到達連結串列末尾時停止,而慢指標會在快指標之前停止,因此它們永遠不會相遇。

相關文章