題目描述:給定兩個已排序陣列 nums1(長度 m)和 nums2(長度 n),請在 O(log(m+n)) 的時間複雜度內找出兩個陣列合併後的中位數。
解題思路:暴力合併後取中位數需要 O(m+n) 時間,題目要求 O(log(m+n)),因此必須使用二分搜尋。
核心概念:中位數將合併後的陣列分為左右兩半,左半部共 (m+n+1)/2 個元素。我們對較短的陣列 nums1 執行二分搜尋,找到一個分割點 i,使得:
nums1 左半部取 i 個元素,nums2 左半部取 j = half - i 個元素。nums1[i-1] <= nums2[j] 且 nums2[j-1] <= nums1[i]。邊界處理:當分割點在邊界時(i=0 或 i=m),用 -INF 或 +INF 代替不存在的元素。
計算中位數:找到正確分割後,左半部最大值 maxLeft = max(nums1[i-1], nums2[j-1]),右半部最小值 minRight = min(nums1[i], nums2[j])。若總長度為奇數,中位數為 maxLeft;若為偶數,中位數為 (maxLeft + minRight) / 2.0。
時間複雜度:O(log(min(m,n))) — 我們對較短的陣列執行二分搜尋,每次將搜尋範圍縮小一半。由於僅對長度較短的陣列二分,複雜度為 O(log(min(m,n))),滿足題目要求的 O(log(m+n))。
空間複雜度:O(1) — 僅使用常數個額外變數,不需要合併兩個陣列或其他輔助空間。
1. Ensure nums1 is the shorter array (swap if needed)
2. Set m = len(nums1), n = len(nums2), half = (m + n + 1) / 2
3. Set lo = 0, hi = m
4. While lo <= hi:
a. i = (lo + hi) / 2 // nums1 partition: i elements on left
b. j = half - i // nums2 partition: j elements on left
c. Define boundary values (use -INF/+INF for out-of-bounds)
d. If nums1[i-1] <= nums2[j] AND nums2[j-1] <= nums1[i]:
- maxLeft = max(nums1[i-1], nums2[j-1])
- If total length is odd: return maxLeft
- Else: return (maxLeft + min(nums1[i], nums2[j])) / 2.0
e. Elif nums1[i-1] > nums2[j]: hi = i - 1
f. Else: lo = i + 1合併後取中位數 O(m+n):將兩個陣列合併(或用雙指標模擬合併),直接取第 (m+n)/2 個元素。實作簡單但時間複雜度不符合題目要求,適合作為驗證答案的基準解法。
第 k 小元素遞迴法 O(log(m+n)):將「求中位數」轉化為「求第 k 小元素」問題。每次比較兩個陣列第 k/2 個元素,排除較小那個陣列的前 k/2 個元素,遞迴縮小問題規模。此方法概念清晰但實作較繁瑣,時間複雜度與分割法相同。