解题思路
给定俩有序数组,找出把它俩合并后所得数组的中位数。要求时间复杂度为O(log(m+n))。
这道题要求我们在对数时间内搞定,我一开始的想法是暴力归并,所以应该是不符合题意的。
因此,我们需要把两个数组各自二分。
中位数是将数组分成数量相等的两半的数(这里会受到奇偶的影响),也就是说对于合并以后长度为N的数组,我们只需要找到它的第(N+1)/2个数或者第(N+1)/2与第N/2个数的均值。
所以我们首先将数组A和数组B分成左右两部分:
left_part | right_part
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1]
B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]
假设A数组是其中较短地数组,我们可以不断地调整A中的i和B中的j使得i+j与m-i+n-j始终相等,
并且左边最大值要小于等于右边最小值。这样我们就能很准确的将左右分割线定在中位数附近了。
至此我们的核心思想就显而易见了:先比较最中间的再向两边扩散。
代码
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m, n, i, j;
int imin, imax, halfPoint;
double maxOfLeft, minOfRight;
//保证nums1长度短于nums2
if (nums1.size() > nums2.size()) {
vector<int> tem_v(nums1);
nums1 = nums2;
nums2 = tem_v;
}
m = nums1.size();
n = nums2.size();
imin = 0;
imax = m;
while (imin <= imax) {
i = imin + imax / 2;
j = (m + n + 1)/2 - i;
if (i > 0 && nums1[i - 1] > nums2[j]) {
imax--;
} else if (i < m && nums2[j - 1] > nums1[i]) {
imin++;
} else {
if (i == 0) maxOfLeft = nums2[j - 1];
else if (j == 0) maxOfLeft = nums1[i - 1];
else maxOfLeft = max(nums1[i-1], nums2[j-1]);
if ((m + n) % 2 == 1) return maxOfLeft;
if (i == m) minOfRight = nums2[j];
else if (j == n) minOfRight = nums1[i];
else minOfRight = min(nums1[i], nums2[j]);
return (minOfRight + maxOfLeft) / 2;
}
}
return 0;
}
复杂度
O(log(min(m,n))