LeetCode4. 尋找兩個正序陣列的中位數 思維和分治
阿新 • • 發佈:2021-11-09
LeetCode4. 尋找兩個正序陣列的中位數
題意
給定兩個大小分別為
m
和n
的正序(從小到大)陣列nums1
和nums2
。請你找出並返回這兩個正序陣列的 中位數 。
演算法
問題轉變為尋找兩個正序陣列中第k
小的數是什麼。
假設m,n >= k/2
,我們分別在nums1
和nums2
陣列分別選取k/2
個數,
nums1[k/2 - 1] > nums2[k/2 - 1]
,可以排除nums2
前k/2
個數肯定不是中位數,接下來需要尋找第k - k/2
數即可。nums1[k/2 - 1] <= nums2[k/2 - 1]
,可以排除nums1
前k/2
個數肯定不是中位數,接下來需要尋找第k - k/2
假設m < k/2
,則我們從nums1
中取m
個元素,從nums2
中取 k/2
個元素(由於 k=(n+m)/
,因此 m
,n
不可能同時小於 k/2
.):
nums1[m - 1] > nums2[k/2 - 1]
,可以排除nums2
前k/2
個數肯定不是中位數,接下來需要尋找第k - k/2
數即可。nums1[m - 1] <= nums2[k/2 - 1]
,可以排除nums1
中的所有數肯定不是中位數,答案為nums2[k - m -1]
數即可。
終止條件& 特殊條件:
- 因為兩個陣列不一定等長,程式交換一下為確保
nums1.size() <= nums2.size()
nums1
全部用完,放回nums2[j+k]
即可。 nums1
有可能不夠k/2
個數,需要特殊判斷if(k == 1)
,返回min(nums1[i], nums2[j])
時間複雜度分析: \(k=(m+n)/2\) ,且每次遞迴 \(k\) 的規模都減少一半,因此時間複雜度是 \(O(\log(m+n))\),
class Solution { public: int dfs(vector<int>& nums1, int i, vector<int>& nums2, int j, int k){ if(nums1.size() - i > nums2.size() - j) return dfs(nums2, j, nums1, i, k); if(nums1.size() == i) return nums2[j + k - 1]; if(k == 1){ if(nums1.size() == i) return nums2[j + k - 1]; else return min(nums1[i], nums2[j]); } int a = min((int)nums1.size(), i + k / 2) - 1, b = j + k / 2 - 1; if(nums1[a] > nums2[b]) return dfs(nums1, i, nums2, b + 1, k - (b - j + 1)); else return dfs(nums1, a + 1, nums2, j, k - (a - i + 1)); } double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int n = nums1.size() + nums2.size(); if(n & 1){ return 1.0 * dfs(nums1, 0, nums2, 0, n / 2 + 1); }else{ return (dfs(nums1, 0, nums2, 0, n / 2) + dfs(nums1, 0, nums2, 0, n / 2 + 1)) / 2.0; } } };