题目:
题解:
又是一道hard题啊,这对于原来就很少做hard的我来说,可以说是很锻炼人了,坐下来静心思考,拿纸笔画结果,写推导过程,终于把这道题搞定了。
思路:
二分法,中位数就是将数组划分为长度相等的两段。
- 1)对于长度为奇数的数组,中位数就是最中间的那个数;对于长度为偶数的数组,中位数就是最中间的两个数的和除以2。也就是说中位数将数组分成长度相等的两段了。
- 2)对于两个有序数组的中位数,nums1的前m1个数和nums2的前m2个数的长度和要为这两个数组总长度的一半,也就是m1+m2=(n1+n2+1)/2
- 3)
nums[m1]
表示nums1中的第m1+1个元素
,在中位数的右边。而nums[m2-1]
表示nums2中第m2个元素
,在中位数的左边。理所应当的中位数右边的要大于左边的,所以nums1[m1]<nums[m2-1]
时,应在nums1的右边区间寻找更大值来使nums[m1]>=nums[m2-1]
(也就是通过增大m1来保证中位数右边的数大于中位数左边的数),即begin=m1+1
;当nums1[m1]>nums[m2-1]
时,我们应该怀疑m1的取值是否过大,所以我们应在nums1的左边寻找更小的m1。最后直至end和begin相等时
跳出循环,也就是end和begin同时指向下标m1,m1在num1表示的是第m1+1个元素,也就是num1[m1+1]。 - 4)最后一步当然是返回中位数了,在nums[m1-1]与nums[m2-1]中取得较大值,若两个数组的总长度为奇数,则直接返回该较大值了。若两个数组的总长度为偶数,则nums[m1]与nums[m2]中取得较小值,然后返回较大值与较小值的平均值。
代码如下:
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int n1=nums1.size(),n2=nums2.size();
if(n1>n2)return findMedianSortedArrays(nums2,nums1);
int begin=0,end=n1;
int k=(n1+n2+1)/2;//k表示中位数
while(begin<end)
{
int m1=begin+(end-begin)/2;
int m2=k-m1;
if(nums1[m1]<nums2[m2-1])//nums1[m1]表示第m1+1个元素,所以nums2中要用下标m2-1
begin=m1+1;
else
end=m1;
}
int m1=end,m2=k-m1;
//num1[m1-1]表示的是nums1中的第m1个元素,nums2[m2-1]表示的是nums2中的第m2个元素
int c1=max(m1<=0?INT_MIN:nums1[m1-1],m2<=0?INT_MIN:nums2[m2-1]);
if((n1+n2)%2==1)//n1与n2的总长度为奇数,返回最中间的元素
return c1;
int c2=min(m1>=n1?INT_MAX:nums1[m1],m2>=n2?INT_MAX:nums2[m2]);
return (c1+c2)/2.0;
}
};