解題說明
Linked List Cycle II
題目描述:給定一個鏈結串列,若存在環,回傳環的起始節點;若不存在環,回傳 null。
解題思路:使用 Floyd 判圈演算法(Floyd's Tortoise and Hare)。第一階段:慢指標每次走一步,快指標每次走兩步,若相遇則確認有環。第二階段:將其中一個指標移回頭節點,兩個指標再以相同速度(每次一步)前進,相遇點即為環的入口。數學證明:設頭到環入口距離為 a,快慢指標相遇點距環入口為 b,環長為 c,則 a = c - b,故從頭與相遇點同速出發必在環入口相遇。此方法不需要任何額外空間。
C++ 解法
複雜度分析
時間複雜度:O(n) — 兩個階段各最多走 O(n) 步。
空間複雜度:O(1) — 只使用兩個指標,不需要額外資料結構。
虛擬碼
1. Initialize slow = head, fast = head
2. Phase 1 - detect cycle:
While fast and fast.next are not null:
slow = slow.next
fast = fast.next.next
If slow == fast: break (cycle found)
3. If no cycle detected, return null
4. Phase 2 - find entrance:
Set ptr = head
While ptr != slow:
ptr = ptr.next
slow = slow.next
5. Return ptr (cycle entrance)其他解法
雜湊集合法:遍歷每個節點,將其加入 unordered_set,若已存在則該節點即為環入口。時間 O(n),空間 O(n),實作簡單但需要額外記憶體。
標記法:將每個訪問過的節點的 next 設為特殊標記節點,但這會破壞原始串列結構,通常不可接受。
延伸思考
- 如何計算環的長度?找到環入口後如何快速求出環的節點數?
- Floyd 演算法的數學推導:為何從頭節點與相遇點同速出發必然在環入口相遇?
- 如果串列中有多個環(非標準情境),演算法需要如何修改?