难度: 困难
题目描述
给定两个大小为 m 和 n 的有序数组 nums1
和 nums2
。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1
和 nums2
不会同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
思路1 归并
先把两个有序数组合并成一个有序数组,再计算出中位数。
class Solution {
public:
double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
vector<int> ans;
for (int i = 0, j = 0, size1 = nums1.size(), size2 = nums2.size(); i < size1 || j < size2;) {
if (i < size1 && j < size2 && nums1[i] < nums2[j] || i < size1 && j == size2)
ans.push_back(nums1[i++]);
else if (i < size1 && j < size2 && nums1[i] >= nums2[j] || j < size2 && i == size1)
ans.push_back(nums2[j++]);
}
if (ans.size() % 2) return ans[ans.size() / 2];
else return (ans[ans.size() / 2] + ans[ans.size() / 2 - 1]) / 2.0;
}
};
思路2 二分答案
设这两个数组中较短的是 a a a,较长的是 b b b, a a a、 b b b的大小分别为 m m m、 n n n,如果能把这些数分成两个大小相等的集合 A A A、 B B B(不能相等则让 A A A大1),且 A A A中的所有元素都不大于 B B B中的所有元素,那么中位数也就确定了。问题就在于如何找到 A A A、 B B B集合在 a a a、 b b b中的界限。设 i i i, j j j分别是 a a a、 b b b数组中属于 B B B集合的最小的数的下标,如果 i i i确定,则 j j j就也随之确定了。对 i i i的位置进行二分是更好的选择,因为 a a a的长度较小,i可能的答案范围是 [ 0 , m + 1 ) [0, m+1) [0,m+1), 0 0 0代表 a a a中元素全部属于 B B B, m m m代表 a a a中元素全部属于 A A A。
class Solution {
public:
double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
vector<int> &a = nums1.size() < nums2.size() ? nums1 : nums2;
vector<int> &b = nums1.size() >= nums2.size() ? nums1 : nums2;
int m = a.size(), n = b.size();
int l = 0, r = m + 1, i = (l + r) / 2, j = (m + n + 1) / 2 - i;
if (m != 0) { // 较小的数组可能为空
for (; l != r; i = (l + r) / 2, j = (m + n + 1) / 2 - i) {
if ((i == 0 || a[i - 1] <= b[j]) && (i == m || b[j - 1] <= a[i])) break;
if (i == 0) l = i + 1; // b[j - 1] > a[i]
else if (a[i - 1] > b[j]) r = i;
else l = i + 1; // i != 0 && a[i - 1] <= b[j] && i != m && b[j - 1] > a[i]
}
}
int lMax = INT_MIN, rMin = INT_MAX;
if (i != 0) lMax = max(lMax, a[i - 1]);
if (j != 0) lMax = max(lMax, b[j - 1]);
if ((m + n) % 2) return lMax;
if (i != m) rMin = min(rMin, a[i]);
if (j != n) rMin = min(rMin, b[j]);
return (lMax + rMin) / 2.0;
}
};