问题描述:
There are two sorted arrays A and B 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)).
如果这题不要求时间复杂度为O(log (m+n)),就变得简单了,直接二路归并,返回排序之后的中位数即可(复杂度O(n))。
算法导论上有一个类似的问题:设X[1..n] 和 Y[1..n]为两个数组,每个都包含n个已排好序的数,给出一个求X和Y中所有2n个元素的中位数的、O(lgn)时间的算法。(第二版,9.3-8)
这两个问题是一致的。
对于一个已排序的序列X[1..n],若n为奇数,则中位数为X[n/2+1],也是其低中位数;若n为偶数,则中位数为(X[n/2]+X[n/2+1])/2,其低中位数是x[n/2]。
对于X[1..m] 和 Y[1..n] 合并之后的数列Z,其低中位数不在X中,就是Y中。
假设Z的low median在X中,用lm表示,在X[k]位置,则在X中有k个元素小于等于lm,有m-k个元素大于等于lm。
在合并之后的序列Z中,low median的位置 = ceil((m+n)/2),用mIndex表示。
我们知道,在序列Z中,一定有mIndex 个元素小于等于lm,有(m+n)-mIndex个元素大于等于lm,所以,在Y中,一定有mIndex - k个元素小于等于lm,有n - (mIndex-k)个元素大于等于lm。
因此,我们可以检查:若Y[mIndex-k]<= X[K] <= Y[mIndex-k+1], 则X[k]是我们要找的low median。边界值发生在k=mIndex, mIndex-k=0, 由于没有Y[0],只需比较X[k] <= Y[1]即可。
当low median不是X[k], 则上面的条件就不成立。
若X[k] <Y[mIndex-k] 则说明low median的位置k' > k
若X[k] > Y[mIndex-k+1] 则说明low median的位置k' < k
由以上分析,我们就可以应用binary search去查找在X中是否存在X[k],使得k<=m && k<mIndex && Y[mIndex-k]<=X[k]<=Y[mIndex-k+1] 或者 k<=m && k=mIndex && X[k] <= Y[1]。如果找到这样的k,这是就是我们要找的low median,否则,一定在Y中,对Y做同样的二分搜索来查找k。
每一个二分查找的时间复杂度为O(lgn),最多两个二分查找:O(lgn) + O(lgm) = O(lg(m+n)
class Solution {
public:
double findMedianSortedArrays(int A[], int m, int B[], int n)
{
int array = 1;
int k = findMedian(A, m, B, n, 1, m);
if(k<0) { k = findMedian(B, n, A, m, 1, n); array = 2; }
if((n+m) % 2)
{
if(array == 1) return A[k-1];
else return B[k-1];
} else {
int medianIndex = (int)ceil((m+n)/2.0);
if(array == 1)
{
if(k < m && medianIndex-k < n)
{
if(A[k] <= B[medianIndex-k]) return (A[k-1] + A[k])/2.0;
else return (A[k-1] + B[medianIndex-k])/2.0;
} else {
if(k >= m) return (A[k-1] + B[medianIndex-k])/2.0;
else return (A[k-1] + A[k])/2.0;
}
} else {
if(k < n && medianIndex-k < m)
{
if(B[k] <= A[medianIndex-k]) return (B[k-1] + B[k])/2.0;
else return (B[k-1] + A[medianIndex-k])/2.0;
} else {
if(k >= n) return (B[k-1] + A[medianIndex-k])/2.0;
else return (B[k-1] + B[k])/2.0;
}
}
}
}
int findMedian(int A[], int m, int B[], int n, int low, int high)
{
int medianIndex = (int)ceil((m+n)/2.0);
int k = 0;
while(low <= high)
{
k = (low+high)/2;
if(k==medianIndex && (n==0 || A[k-1] <= B[medianIndex - k]))
{
return k;
}
else {
if(k>medianIndex)
{
high = k-1;
continue;
}
if(k<medianIndex && (medianIndex-k-1<n && A[k-1]>=B[medianIndex-k-1]) && (medianIndex-k>=n || A[k-1] <= B[medianIndex-k]))
{
return k;
} else {
if(medianIndex-k-1>=n || (medianIndex-k-1>=0 && A[k-1]<B[medianIndex-k-1])) { low = k+1; continue; }
else { high = k-1; continue; }
}
}
}
return -1;
}
};
不过,这题有更好的解法,把题目抽象成更普遍的一个问题,寻找两个有序序列第k大值问题。
这里有一个清晰明了的解法: http://blog.csdn.net/yutianzuijin/article/details/11499917