LeetCode - Median of Two Sorted Arrays

来源:互联网 发布:卡尔.拉格斐 知乎 编辑:程序博客网 时间:2024/05/05 07:06

问题描述:

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


0 0