题目描述
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
示例
示例一:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例二:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
题解
中位数的意义:将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。
分别将nums1和nums2划分为两个子集,划分位置定义为i和j,将nums1Left和nums2Left合并称为Left,将nums1Right和nums2Right合并称为right。要确保left中的元素小于right中的元素,即nums1Left[i-1]要小于nums2Right[j],nums2Left[j-1]要小于nums1right[i]。
如果上述条件成立则证明我们找到了目标对象;
起初设定i=nums1.length/2;j=(nums1.length+nums2.length+1)/2-i;(前提假设m小于等于n,因为j不能为负值)
如果nums1Left[i-1]>nums2Right[j],则证明i太大了,应该减小,因为i越小,nums1Left[i-1]就会减小,j会增大,则nums2Right[j]也会增大。
如果nums2Left[j-1]>nums1Right[i],则证明i太小了,应该增大,因为i越大,nums1Right[i]就会增大,j则会减小,nums1Left[j-1]就会减小。
double median=0.0;
int m=nums1.length,n=nums2.length;
if(m>n) {
int []temp=nums1;nums1=nums2;nums2=temp;
int tmp=m;m=n;n=tmp;
}
int imin=0,imax=m,halfLen=(m+n+1)/2;
while(imin<=imax) {
int i=(imin+imax)/2;
int j=halfLen-i;
if(i>imin&&nums1[i-1]>nums2[j])// i too big
imax=i-1;
else if(i<imax&&nums2[j-1]>nums1[i])//i too small
imin=i+1;
else {
double maxLeft=0,minRight=0;
if(i==0)
maxLeft=nums2[j-1];
else if(j==0)
maxLeft=nums1[i-1];
else
maxLeft=Math.max(nums1[i-1], nums2[j-1]);
if((m+n)%2!=0)
return maxLeft;
if(i==m)
minRight=nums2[j];
else if(j==n)
minRight=nums1[i];
else
minRight=Math.min(nums1[i], nums2[j]);
median=(maxLeft+minRight)/2.0;
return median;
}
}
return median;
}