leetcode 4. 寻找两个有序数组的中位数
4. 寻找两个有序数组的中位数
问题描述
给定两个大小为 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.如果对数组的个数分奇偶讨论,则过于繁琐,如果一个数组为a[3]={1,2,3},其中位数直接取a[3/2+1](即len/2+1个数即可),但是如果数组个数是偶数,a[4]={1,2,3,4},其中位数为(a[4/2+1]+a[4/2])/2,即要考虑第len/2-1与第len/2个元素的平均值。但是我们换一种表示,如果长度len是奇数,我们也取平均值,是(a[(len+1)/2]+a[(len+2)/2])/2,显然a[(len+1)/2]=a[(len+2)/2]是同一个数,即取了两次而已。如果长度len是偶数,则(a[(len+1)/2]+a[(len+2)/2])/2 = (a[len/2+1]+a[len/2])/2(注意此处的除法是计算机的除法,有下取整,找中位数,因此考虑的下标从1开始而不是从0开始);
2.因为要求复杂度为O(log(m+n)),因此需要使用二分法;
3.寻找中位数的问题转化为寻找第k大的问题,因此可以将两个数组分为两部分,各自查找自己的前k/2个元素。
代码
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size(), n = nums2.size();
return (findKth(nums1,0,nums2,0,(m+n+1)/2)+findKth(nums1,0,nums2,0,(m+n+2)/2))/2.0;
}
//start1是nums1的将要查询起始位置,stzrt2是nums2将要查询的起始位置
int findKth(vector<int>& nums1,int start1,vector<int>& nums2,int start2,int k)
{
int len1 = nums1.size(),len2 = nums2.size();
if(len1 <= start1) return nums2[start2+k-1];//数组nums1为空,因此只需要找nums2的第k小的元素即可
if(len2 <= start2) return nums1[start1+k-1];//数组nums2为空
if(k == 1) return min(nums1[start1],nums2[start2]);//递归边界
//在nums1和nums2中各自查询前k/2个元素,如果nums1[start1+k/2-1]<nums2[start2+k/2-1],这说明第k小的元素
//一定不在nums2的前k/2-1个元素之中,反之则不在nums1的前k/2-1个元素之中
int var1 = (start1 + k/2 - 1 < len1)? nums1[start1+k/2-1]:2147483647;
int var2 = (start2 + k/2 - 1 < len2)? nums2[start2+k/2-1]:2147483647;
if(var1 < var2){
return findKth(nums1,start1+k/2,nums2,start2,k-k/2);
}
else
return findKth(nums1,start1,nums2,start2+k/2,k-k/2);
}
};