題目描述:給定一個包含 n + 1 個整數的陣列 nums,其中每個整數都在 [1, n] 範圍內。根據鴿巢原理,陣列中必定存在至少一個重複的數字。請找出並返回那個重複的數字。限制條件:不能修改原陣列,且只能使用 O(1) 額外空間。
解題思路:此題最優解是 Floyd's Cycle Detection(Floyd 判圈演算法,龜兔賽跑算法),將陣列視為一個隱式的鏈結串列來處理。
為何其他方法不完全符合要求?
Floyd's Cycle Detection 的核心思想:
將每個索引 i 視為節點,將 nums[i] 視為從節點 i 指向節點 nums[i] 的邊,構成一個隱式的有向圖。由於有重複數字,必然存在兩個不同的索引指向同一個節點,從而形成環。
三個步驟:
slow = nums[slow]),快指標每次走兩步(fast = nums[nums[fast]]),直到相遇。時間複雜度:O(n) — Floyd 判圈演算法分兩個階段:第一階段找相遇點,第二階段找環的入口。兩個階段的走訪步數均與串列長度(即陣列長度 n)成線性關係,因此整體時間複雜度為 O(n)。
空間複雜度:O(1) — 整個演算法只使用了兩個指標變數(slow 和 fast),不需要哈希表、額外陣列或任何與輸入規模成比例的輔助空間,完全滿足題目的空間限制要求。
1. Initialize slow = nums[0], fast = nums[0]. 2. Phase 1 — detect cycle: a. Repeat: slow = nums[slow], fast = nums[nums[fast]]. b. Stop when slow == fast (intersection point found). 3. Phase 2 — find cycle entrance: a. Reset slow = nums[0]; keep fast at the intersection point. b. Move both slow and fast one step at a time: slow = nums[slow], fast = nums[fast]. c. Stop when slow == fast. 4. Return slow (or fast) — this is the duplicate number.
哈希表 O(n) 時間 / O(n) 空間:走訪陣列,將每個數字存入哈希集合,若發現數字已存在則直接返回。實作最簡單,但需要 O(n) 額外空間,不符合本題的空間限制,僅適合作為暴力解或快速驗證答案使用。
二分搜尋(按值域)O(n log n) 時間 / O(1) 空間:對值域 [1, n] 進行二分搜尋。對於中間值 mid,統計陣列中小於等於 mid 的數字個數 count。若 count > mid,代表重複數字在 [1, mid] 範圍內;否則在 [mid+1, n] 範圍內。此方法滿足空間限制,但時間複雜度為 O(n log n),不如 Floyd 演算法的 O(n) 優秀,且僅在重複數字只出現兩次時保證正確。
排序後線性掃描 O(n log n) 時間:先對陣列排序,再線性掃描找到相鄰相等的數字。此方法違反「不得修改原陣列」的限制,不符合題意。