题目链接
解法
直接排序法
对于这道题,最直接粗暴的办法是把两个数组合并起来排序,然后直接肝出新数组的中位数即答案。但是时间复杂度无法达标,为.
class Solution {
public:
double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
vector<int> ans;
ans.resize(nums1.size() + nums2.size());
merge(nums1.begin(), nums1.end(), nums2.begin(), nums2.end(), ans.begin());
sort(ans.begin(), ans.end());
int len = ans.size();
if (len % 2 == 1)
return ans[len / 2];
else
return (double) (ans[len / 2] + ans[len / 2 - 1]) / 2;
}
};
递归法()
原问题有点难以递归,我们不妨考虑一个比较简单的问题:
在两个大小分别为n和m的有序数组中,找出总排名第k小的数.
如果这个问题可以解决,那么只要找到第 大的数字即是我们所求的中位数(元素总数是奇数没问题,是偶数的话需要找到第 大与第 大的数字取平均,但我们现在先不用考虑这么多)。
先考虑最简单的情况,两个数组的元素数量均充足,即,我们就可以先在每个数组里各取个元素:
- 如果 ,则说明在 数组中,前 个元素都小于第小的数字,可能还有“漏网之鱼”;而在数组的前 个元素中,可能有比第 小的数字大的数字被我们误取。所以我们的办法是,将的前个元素全部拿走(因为已知它们都小于第 小个数字,不是我们要找的),将问题递归成在剩下的数字中寻找第 小数。
- 如果 ,同理可说明 中的前 个元素一定都小于等于第 小数,类似可将问题的规模减少一半.
现在,我们考虑边界情况。如果 ,则我们从 取 个元素,从 中取 个元素(由于 ,因此 和 不可能同时小于 。
- 如果 ,则 中的前 个元素一定都小于等于第 小数,我们可以将问题归约成在剩下的数中找第 小数.
- 如果 ,则 中的所有元素一定都小于等于第 小数,因此第小数是 .
话不多说,上代码。代码里细节点很多,建议自己看懂后复写一遍。
class Solution {
public:
double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
int total = nums1.size() + nums2.size();
if (total % 2 == 0) {
int left = findKthNumber(nums1, 0, nums2, 0, total / 2);
int right = findKthNumber(nums1, 0, nums2, 0, total / 2 + 1);
return (left + right) / 2.0;
} else
return findKthNumber(nums1, 0, nums2, 0, total / 2 + 1);
}
int findKthNumber(vector<int> &nums1, int i, vector<int> &nums2, int j, int k) {
if (nums1.size() - i > nums2.size() - j) return findKthNumber(nums2, j, nums1, i, k);
if (nums1.size() == i) return nums2[j + k - 1];
if (k == 1) return min(nums1[i], nums2[j]);
int si = min(int(nums1.size()), i + k / 2), sj = j + k / 2;
if (nums1[si - 1] > nums2[sj - 1])
return findKthNumber(nums1, i, nums2, j + k / 2, k - k / 2);
else
return findKthNumber(nums1, si, nums2, j, k - (si - i));
}
};