Description:
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
Discuss:
参考本题排名第一的discuss的思路如下,最终时间复杂度为 O ( log(min( m , n ) )
1.分析问题:
首先理解中位数是以什么,在统计学中,中位数是用来把一个集合分成两个长度相等的子集,并且一个子集大于另一个子集,即一个子集中的任意元素大于另一个子集中的任意元素。
这里有两点条件,长度相等,任意元素大于。所以列出下面的模型,为了后面便于思考
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]
其中
m:A数组长度
n:B数组长度
i:A数组的分割点,一共有m+1个分割点,i=0,1,2...m
j:B数组的分割点,一共有n+1个分割点,j=0,1,2...n
2.找出判断条件:
根据中位数的性质,得出判断条件为:
(1) len(left_part) == len(right_part)
(2) max(left_part) <= min(right_part)
首先设置n>=m,原因如下:
即设置数组A为长度较小的数组。如果数组A的长度大于数组B的长度,A的分割点无法到取到靠后的位置,因为可能会使leftA的长度大于rightA+lenB的长度。这样i就可以任意取,i , j 结果都为正,我们只要考虑 i的范围即可,有序数组的查找显然后面可以使用二分法。
继续推导判断条件,有两种情况:
<1> 当m+n为偶数时,中位数是中间两数之和,若想找到正确的i,应该有:
(1) i + j == m - i + n - j
(2) B[j-1] <= A[i] and A[i-1] <= B[j]
最后的结果为 (max(A[i-1], B[j-1]) + min(A[i], B[j]))/2
<2> 当m+n为奇数时,中位数是中间的一个数,把中间的数归到左半部分,则有:
(1) i + j == m - i + n - j + 1
(2) B[j-1] <= A[i] and A[i-1] <= B[j]
这时最后的结果为 max(A[i-1], B[j-1])
我们之前设置过i是可以任意取值的,于是有j=(m+n)/2-i,并且其中j > 0。
当m+n为偶数时,(m+n)/2==(m+n+1)/2,所以以上两种情况的判断条件可以合并,但两种情况的中位数结果是不同的,于是得到最终判断条件为:
(1) i = 0 ~ m, j = (m + n + 1)/2 - i
(2) B[j-1] <= A[i] and A[i-1] <= B[j]
3.确定循环过程:
根据上面的特点,可以对i使用二分法查找,并且根据之前对奇偶情况结果的讨论,需要保存left_part_max和right_part_min。
设置imin=0,imax=m,i=(imin+imax)/2,则对于一个给定的i,有如下几种情况:
搜索过程:
<1> B[j-1] > A[i] && i < m , 需要增加i,令imin=i+1
<2> A[i-1] > B[j] && i > 0 , 需要减小i,令imax=i-1
备注:(i小于m时,因为m<=n,j若等于0,右半部分元素会过多,所以j一定大于0)
(i大于0时,因为m<=n,j若等于n,左半部分元素会过多,所以j一定小于n)
判定结果,有以下几种解的情况:
<1>i == 0 && j != n
<2>i == 0 && j == n
<3>i == m && j != 0
<4>i == m && j ==0
<5>0 < i < m && B[j-1] <= A[i] && A[i-1] <= B[j]
备注:如果在二分的过程中,i取到边界0或m,显然已进行到二分法循环的边界,所以这时i一定是最后的正确的取值。每一步都需要设置对应的left_part_max和right_part_min。
设置left_part_max和right_part_min:
边界情况,当i=0,i=m,j=0,j=n,即某一part中只含有单个数组的元素,则这部分part的最值就是被分到这个part的数组中的元素的最值。于是有如下对应的part的最值
<1>leftmax=B[j-1] rightmin=min(A[i],B[j])
<2>leftmax=B[j-1] rightmin=A[i]
<3>leftmax=max(A[i-1],B[j-1]) rightmin=B[j]
<4>leftmax=A[i-1] rightmin=B[j]
<5>leftmax=max(A[i-1],B[j-1]) rightmin=min(A[i],B[j])
综上所述,可以用类似笛卡尔积的形式,以两个if-else语句块分别表达出leftmax和rightmin结果:
if(i==0)
leftmax=B[j-1];
else if(j==0)
leftmax=A[i-1];
else
leftmax=max(A[i-1],B[j-1]);
if(i==m)
rightmin=B[j];
else if(j==n)
rightmin=A[i];
else
rightmin=min(A[i],B[j]);
时间复杂度:
二分法的时间复杂度为O( logx ),显然本题的时间复杂度为O ( log(min( m , n ) )
代码:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
if(nums1.size()>nums2.size()){
vector<int> temp=nums1;
nums1=nums2;
nums2=temp;
}
int m=nums1.size(),n=nums2.size();
int imin=0,imax=m;
int leftmax,rightmin;
while (imin<=imax)
{
int i=(imin+imax)/2;
int j=(m+n+1)/2-i;
if(i>0&&nums1[i-1]>nums2[j])//j<n
imax=i-1;//decrease i
else if(i<m&&nums1[i]<nums2[j-1])//j>0
imin=i+1;//increase i
else{
if(i==0)
leftmax=nums2[j-1];
else if(j==0)
leftmax=nums1[i-1];
else
leftmax=max(nums1[i-1],nums2[j-1]);
if((m+n)%2==1)
return leftmax;
if(i==m)
rightmin=nums2[j];
else if(j==n)
rightmin=nums1[i];
else
rightmin=min(nums1[i],nums2[j]);
return (leftmax+rightmin)/2.0;
}
}
}