每日演算法隨筆:環形連結串列

鱼摆摆不摆發表於2024-09-10

題解:環形連結串列

在這道題目中,我們需要判斷一個連結串列是否存在環。環的定義是連結串列的某個節點可以透過連續跟蹤 next 指標回到自身。如果存在這樣的環,那麼就返回 true,否則返回 false

方法一:使用雜湊集合 (HashSet)

思路

  • 遍歷連結串列,使用一個雜湊集合 (HashSet) 儲存每個訪問過的節點。
  • 每遍歷一個節點時,檢查該節點是否已經存在於集合中。如果存在,說明連結串列中存在環;如果不存在,則將該節點加入集合中。
  • 如果遍歷完整個連結串列都沒有發現重複節點,說明連結串列中不存在環。

程式碼實現

/**
 * 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) {
        Set<ListNode> set = new HashSet<ListNode>();
        ListNode curr = head;
        while (curr != null) {
            // 如果當前節點已經在集合中,說明有環
            if (!set.add(curr)) {
                return true;
            }
            curr = curr.next; // 繼續遍歷下一個節點
        }
        return false; // 如果遍歷到連結串列末尾沒有發現環
    }
}

複雜度分析

  • 時間複雜度:O(n),其中 n 是連結串列的節點數。我們每個節點只遍歷一次。
  • 空間複雜度:O(n),需要額外的雜湊集合來儲存每個訪問的節點。

過程解析

  1. 初始化一個空的 HashSet
  2. 從頭節點開始遍歷連結串列,每遇到一個節點,檢查它是否在 HashSet 中。如果在,說明有環,返回 true;否則,將該節點加入集合,繼續遍歷下一個節點。
  3. 如果遍歷到了連結串列的末尾(即 curr == null),說明連結串列沒有環,返回 false

方法二:快慢指標 (Floyd 判圈演算法)

思路

  • 使用兩個指標:一個快指標 (fast),一個慢指標 (slow)。
  • 快指標每次走兩步,慢指標每次走一步。
  • 如果連結串列中沒有環,快指標會在遍歷完連結串列時到達 null
  • 如果連結串列中有環,快指標會最終追上慢指標,兩者會相遇。

程式碼實現

/**
 * 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) return false;

        ListNode slow = head; // 慢指標
        ListNode fast = head.next; // 快指標

        // 快慢指標相遇說明有環
        while (fast != slow) {
            if (fast == null || fast.next == null) return false; // 快指標提前到達終點,說明沒有環
            fast = fast.next.next; // 快指標走兩步
            slow = slow.next; // 慢指標走一步
        }

        return true; // 兩個指標相遇,說明有環
    }
}

複雜度分析

  • 時間複雜度:O(n),其中 n 是連結串列的節點數。最壞情況下,快指標和慢指標遍歷連結串列中的每個節點。
  • 空間複雜度:O(1),我們只用了常數級別的額外空間。

過程解析

  1. 快指標 fast 每次走兩步,慢指標 slow 每次走一步。
  2. 如果連結串列中有環,快指標最終會追上慢指標,這時返回 true
  3. 如果快指標在遍歷過程中到達了 null,則連結串列沒有環,返回 false

方法比較:

  1. 雜湊集合法使用了額外的儲存空間,但思路簡單易懂,適合初學者。
  2. 快慢指標法雖然稍微複雜一點,但它不需要額外的空間,能夠以 O(1) 的空間複雜度解決問題,在面試中常被要求使用這種方法。

這道題目考察了連結串列的基本操作以及快慢指標的應用,透過分析連結串列的結構,可以更好地掌握連結串列與指標的使用。

相關文章