LeetCode4. 寻找两个正序数组的中位数 思维和分治
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;
}
}
};