思路:
首先最容易的想到的是新开一个数组C[n+m],将数组A和B的值赋到C中,快排,找中数,时间复杂度为O((n+m)log(n+m))和空间复杂度为O(n+m)。这种方法完全没有利用到A、B是有序数组的条件,因此复杂度较高。
第二种方法是利用A、B是有序数组,用两个指示变量 i ,j 分别指向A和B的第一个元素,通过比较A[i]与B[j]:若A[i]<B[j],i++;否则 j++,知道找到第(n+m)/2点。时间复杂度为O(n+m)。
以上两种方法均达不到题目对复杂度为O(log(n+m))的要求,还需要进一步优化。
我们先将问题转化为更一般的问题:寻找第k小的数。首先假设数组A和B的元素个数都大于k/2,我们比较A[k/2-1]和B[k/2-1]两个元素,这两个元素分别表示A的第k/2小的元素和B的第k/2小的元素。这两个元素比较共有三种情况:>、<和=。
1、A[k/2-1] < B[k/2-1],这表示A[0]到A[k/2-1]的元素都在A和B合并之后的前k小的元素中。换句话说,A[k/2-1]不可能大于两数组合并之后的第k小值,所以我们可以将其抛弃。
2、A[k/2-1] < B[k/2-1],与情况1类似。
3、A[k/2-1] = B[k/2-1],则A[k/2-1]或B[k/2-1]即为第k小的数。
注:仔细想想,其实方法三是由方法二衍生而来的,第二种方法是每次抛弃一个元素(i++ or j++),而方法三是一次抛弃k/2个数据,提高了效率。
代码:
方法二:
class Solution {
public:
double findMedianSortedArrays(int A[], int m, int B[], int n) {
int len=n+m;
int target=(n+m)/2;
int i=0,j=0;
int a[m+n+5],ans=0;
while(ans<=target)
{
if(j==n)
{
a[ans++]=A[i];
i++;
continue;
}
if(i==m)
{
a[ans++]=B[j];
j++;
continue;
}
if(A[i]>B[j])
{
a[ans++]=B[j];
j++;
}
if(A[i]<=B[j])
{
a[ans++]=A[i];
i++;
}
}
double median;
if(len&1)
median=(double)a[target];
else
median=(double)(a[target]+a[target-1])/2;
return median;
}
};
方法三 :
class Solution {
public:
double findk(int A[], int m, int B[], int n, int k)
{
if(m>n)
return findk(B,n,A,m,k);
if(m==0)
return B[k-1];
if(k==1)
return min(A[0],B[0]);
int k1=min(m,k/2);
int k2=k-k1;
if(A[k1-1]<B[k2-1])
return findk(A+k1,m-k1,B,n,k-k1);
else if(A[k1-1]>B[k2-1])
return findk(A,m,B+k2,n-k2,k-k2);
return A[k1-1];
}
double findMedianSortedArrays(int A[], int m, int B[], int n) {
int k=m+n;
if(k&1)
return findk(A,m,B,n,k/2+1);
return (findk(A,m,B,n,k/2)+findk(A,m,B,n,k/2+1))/2;
}
};