题目链接:https://leetcode.com/problems/median-of-two-sorted-arrays/
给出两个有序数组,求得两个数组的中位数。时间复杂度要log(n+m)。
题意简单,但属实有些不好想。有序,时间复杂度要log。很容易想到二分。
先考虑偶数的情况。数组可以分成两个部分。
left right
A[0],A[1],……A[i-1], | A[i],A[i+1],……A[n-1]
B[0],B[1],……B[j-1], | B[j],B[j+1],……B[m-1]
两个部分要满足以下条件:
- 左右个数left=right
- left的最大值要小于等于right的最小值。即:A[i-1]<=B[j]且B[j-1]<=A[i]
那么中位数为(max(A[i-1],B[j-1])+min(A[i],B[j]))/2。
该题的难点在于如何使用二分求得两个数组的i,j位置。
我们可以寻找i,j之间的关系。因为左右两边个数相等,所以:
i + j = n - i + m - j
i + j = (n + m) / 2
j = (n + m ) / 2 - i;
这里要注意考虑j的取值
j不能为负数,其中i的取值为[0,n]。
所以不等式要满足 :
(n+m)/ 2 >= n,即 m>=n。
再考虑奇数的情况,奇数情况是左边的个数比右边的个数多一个,所以第一个条件变为
left = right + 1
而此时的中位数为:max(A[i-1],B[j-1])
i,j之间的关系变为:
i + j = n - i + m - j + 1
j = (n + m + 1) / 2 - i;
但是因为是int的计算,所以j = (n + m + 1) / 2 - i的情况包含了j = (n + m ) / 2 - i;的情况。所以我们使用j = (n + m + 1 ) / 2 - i;计算即可。
所以使用二分的方法求 i ,然后通过公式求得 j。
当此时的 i ,j 满足 A[i-1]<=B[j]且B[j-1]<=A[i],即可求得其中位数。
但是到目前为止我们没有考虑i,j是边界和数组为空的情况。比如:
left right
A[0],A[1],……A[n-1], | A[i] //注意此时A[i]并不存在,只是为了说明。
B[0],B[1],……B[j-1], | B[j],B[j+1],……B[m-1]
left right
A[i-1] | A[0],A[1],……A[n-1], //注意此时A[i-1]并不存在,只是为了说明。
B[0],B[1],……B[j-1], | B[j],B[j+1],……B[m-1]
left right
| //注意此时A不存在,只是为了说明。
B[0],B[1],……B[j-1], | B[j],B[j+1],……B[m-1]
当i,j是边界情况时,此时的我们只需要满足 A[i-1]<=B[j]或B[j-1]<=A[i]或者这个条件没有存在必要。
代码如下:
class Solution {
public:
double findMedianSortedArrays(vector<int>& A, vector<int>& B) {
int lena = A.size();
int lenb = B.size();
if(lena>lenb)
return findMedianSortedArrays(B,A);
int l=0,r=lena;
int t = (lena+lenb+1)/2;
double ans=-1;
while(l<=r){
int i=(l+r)>>1;
int j=t-i;
// printf("%d %d\n",i,j);
if(i<r&&A[i]<B[j-1]){
l+=1;
}
else if(i>l&&A[i-1]>B[j]){
r-=1;
}
else{
double maxl;
if(i==0){
maxl=B[j-1];
}
else if(j==0){
maxl=A[i-1];
}
else{
maxl=max(A[i-1],B[j-1]);
}
if((lena+lenb)%2){
ans = maxl;
break;
}
double minr;
if(i==lena){
minr=B[j];
}
else if(j==lenb)
{
minr=A[i];
}
else
{
minr=min(A[i],B[j]);
}
ans = (maxl+minr)/2;
//printf("%d %d\n",maxl,minr);
break;
}
}
return ans;
}
};