给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
通过次数829,238提交次数1,995,256
这题有两种思路,1递归,2二分,二分有点难以理解,这里递归是最简单的解法。
把找两个数组的中位数转换为找第k个数。要查找的k即为总长度的一半(中位数)
首先每次都分别取出两个数组的中位数(k/2)
有三种情况
1. nums1[k/2] > nums2[k/2]
此时nums2数组中的前k/2个数不可能是第k个数,可以直接删除,接下去遍历时寻找第nums2中k - k / 2和nums1中的全部即可
2. nums1[k/2] < nums2[k/2] 刚好相反
3.nums1[k/2] = nums2[k/2],此时任意输出一个就可
class Solution {
public:
double findMedianSortedArrays(vector& nums1, vector& nums2) {
int total = nums1.size() + nums2.size();
if(total % 2) return find(nums1, 0, nums2, 0, total / 2 + 1);//奇数直接返回中间值
else {//偶数返回两数的平均数
int left = find(nums1, 0, nums2, 0, total / 2);
int right = find(nums1, 0, nums2, 0, total / 2 + 1);
return (left + right) / 2.0;
}
}
//k从1开始
int find(vector& nums1, int i, vector& nums2, int j, int k)
{
//假定nums1的长度较小,方便code
if(nums1.size() - i > nums2.size() - j) return find(nums2, j, nums1, i, k);
//若nums1长度为0,则直接返回第二个数组中的第k个元素
if(nums1.size() == i) return nums2[j + k - 1];
//如果k=1,返回两个数头部较小的元素
if(k == 1) return min(nums1[i], nums2[j]);
//三种情况
int si = min((int)nums1.size() - 1, i + k / 2 - 1), sj = j + k - k / 2 - 1;//两个数组分别的中点
if(nums1[si] > nums2[sj])
return find(nums1, i, nums2, sj + 1, k - (sj - j + 1));
else
return find(nums1, si + 1, nums2, j, k - (si - i + 1));
}
};