給定單向鏈表頭節點 `head`,判斷鏈表中是否有環。無法修改鏈表,空間複雜度最好 O(1)。
時間 O(N),空間 O(N)。面試常被要求優化空間。
對第 k 個節點,檢查前 k-1 個是否相同。時間 O(N²),N=5000 會 TLE。
**核心洞見**:若有環,快指針(每次 2 步)終將追上慢指針(每次 1 步),如同操場跑道雙人跑。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if (!head || !head->next) return false;
ListNode *slow = head;
ListNode *fast = head->next; // 或 head,邏輯微調
while (fast && fast->next) {
if (slow == fast) return true; // 相遇 → 有環
slow = slow->next;
fast = fast->next->next;
}
return false; // fast 走到 null → 無環
}
};
| 細節 | 處理 |
|---|---|
| 空鏈表/單節點 | 開頭直接返回 false |
| fast 初始位置 | `head` 或 `head->next` 皆可,只影響相遇步數 |
| 迴圈條件 | `fast && fast->next` 確保 `fast->next->next` 安全 |
| 相遇判斷 | 指標地址相等,非 `val` 相等 |
| 時間複雜度 | O(N):快指針最多繞環 1 圈追上 |
| 空間複雜度 | O(1):只用兩指針 |
相遇後,將一指針重置為 head,兩指針同速(1 步)前進,再次相遇點即為環入口。證明:相遇時慢指針走 a + x,快指針走 2(a+x) = a + x + kb → a = kb - x。從 head 走 a 步到入口,從相遇點走 kb - x 步也到入口。
快慢指針是鏈表環問題的「核武級」武器:O(1) 空間、O(N) 時間、代碼極簡。掌握其核心邏輯與邊界處理,同類問題迎刃而解。