問題
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
輸入
- nums1 = [1, 3]
nums2 = [2]
- nums1 = [1, 2]
nums2 = [3, 4]
輸出
- The median is 2.0
- The median is (2 + 3)/2 = 2.5
分析
要注意題目中的數組已經排序好了。排序數組,復雜度又要求是O(log(m+n)),很容易聯想到二分搜索。
舉個例子,有兩個排序數組,分別為:
A:1 3 5
B:2 4 6 8
顯然,中位數應該是兩個數組所有元素從小到大排序后的第4個數。
首先,我們比較兩個數組的第4/2=2個數,A的第2個數為3,B的第2個數為4,A[2] < B[2](為了方便起見,索引從1開始)。我們可以確定中位數不會在A[1]-A[2]范圍中,這樣就把搜索范圍縮小了4/2個。
擴展到一般情況,每次比較A[k/2]和B[k/2]之后,都可以把A或者B的搜素范圍縮小一半,即不斷地二分,計算復雜度為O(log(m+n))。
要點
二分搜索 遞歸
時間復雜度
O(log(m+n))
空間復雜度
O(log(m+n)),遞歸需要棧空間
代碼
class Solution {
public:
int findKthNum(const vector<int> &a, int begA, const vector<int> &b, int begB, int k)
{
if (a.size() - begA > b.size() - begB) // 始終保持a的長度小于b,避免以后不必要的分情況討論
return findKthNum(b, begB, a, begA, k);
if (a.size() - begA == 0) // 如果a的搜索空間為空,直接返回b的第k個數
return b[begB + k - 1];
if (k == 1) // 如果k為1,直接返回a和b的搜索空間的第一個值的最小值
return min(a[begA], b[begB]);
int pa = min(k / 2, (int)(a.size()) - begA); // 避免pa大于a的搜索空間的大小
int pb = k - pa;
if (a[begA + pa - 1] == b[begB + pb - 1]) // 如果相等,說明已經找到了中位數
return a[begA + pa - 1];
else if (a[begA + pa - 1] < b[begB + pb - 1])
return findKthNum(a, begA + pa, b, begB, k - pa); // 二分a
else
return findKthNum(a, begA, b, begB + pb, k - pb); // 二分b
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size() + nums2.size();
// 對n的奇偶性分情況討論
if (n & 0x1)
{
return findKthNum(nums1, 0, nums2, 0, n / 2 + 1);
}
else
{
return (findKthNum(nums1, 0, nums2, 0, n / 2) + findKthNum(nums1, 0, nums2, 0, n / 2 + 1)) / 2.0;
}
}
};