[LeetCode] Median of Two Sorted Arrays

 

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)).

分析:

(1)median is the middle value in an ordered integer list. If the size of  the list is even, there is no middle value. So the median is the mean of the two middle value.

Examples:

  • [2,3,4] , the median is 3

  • [2,3], the median is (2 + 3) / 2 = 2.5

(2)logm+logn = log(mn)  <= log( (m + n)  ^ 2) =2 log(m + n)  ?= O(log(m + n))

方法1:归并排序的最后一步,相当于把两个长度分别为m和n的子数组合并成有序的一个数组,合并后找出median,这样做的时间复杂度是O(m+n),需要额外空间O(m+n);

class Solution {
public:
    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        int *C = new int[m+n];
        memcpy(C,A,sizeof(int)*m);
        memcpy(C+m,B,sizeof(int)*n);
        
        int med = (m+n)/2;
        sort(C,C+m+n);
        double median;
        if((m+n)%2)
        {
            median = (double)C[med];
            
        }
        else
            median = (double) (C[med]+C[(med-1)])/2; 
           
        delete []C;
        return median; 
    }
};

 

方法2:用两个指针分别指向两个数组的开头,哪个指针指向的数小则指针往前走一步,走k步之后(k=(m+n)/2),指针指向的值即是

我们需要找的median,时间复杂度O(k),不需要额外的空间,即空间复杂度O(1);

方法3:最好的时间复杂度O(log (m+n)),思路:Sorted Arrays -> Binary Search -> achieving logarithmic complexity,

从排序数组就联想到二分查找的思路来考虑问题。

参考博客:http://blog.csdn.net/yutianzuijin/article/details/11499917

按寻找第k小数的思路,则k=(m+n)/2

(1)首先假设数组A和B的元素个数都大于k/2,我们比较A[k/2-1]和B[k/2-1]两个元素,这两个元素分别表示A的第k/2小的元素和B的第k/2小的元素。这两个元素比较共有三种情况:>、<和=。如果A[k/2-1]<B[k/2-1],这表示A[0]到A[k/2-1]的元素都在A和B合并之后的前k小的元素中。换句话说,A[k/2-1]不可能大于两数组合并之后的第k小值,所以我们可以将其抛弃。

证明也很简单,可以采用反证法。假设A[k/2-1]大于合并之后的第k小值,我们不妨假定其为第(k+1)小值。由于A[k/2-1]小于B[k/2-1],所以B[k/2-1]至少是第(k+2)小值。但实际上,在A中至多存在k/2-1个元素小于A[k/2-1],B中也至多存在k/2-1个元素小于A[k/2-1],所以小于A[k/2-1]的元素个数至多有k/2+ k/2-2,小于k,这与A[k/2-1]是第(k+1)的数矛盾。

(2)当A[k/2-1]>B[k/2-1]时存在类似的结论。

(3)当A[k/2-1]=B[k/2-1]时,我们已经找到了第k小的数,也即这个相等的元素,我们将其记为m。由于在A和B中分别有k/2-1个元素小于m,所以m即是第k小的数。(这里可能有人会有疑问,如果k为奇数,则m不是中位数。这里是进行了理想化考虑,在实际代码中略有不同,是先求k/2,然后利用k-k/2获得另一个数。)

通过上面的分析,我们即可以采用递归的方式实现寻找第k小的数。此外我们还需要考虑几个边界条件:

 

  • 如果A或者B为空,则直接返回B[k-1]或者A[k-1];
  • 如果k为1,我们只需要返回A[0]和B[0]中的较小值;
  • 如果A[k/2-1]=B[k/2-1],返回其中一个;

 

最终实现的代码为:

#include<iostream>
#include<algorithm>
using namespace std;

double findKth(int a[], int m, int b[], int n, int k)  
{  
    //always assume that m is equal or smaller than n  
    if (m > n)  
        return findKth(b, n, a, m, k);  
    if (m == 0)  
        return b[k - 1];  
    if (k == 1)  
        return min(a[0], b[0]);  
    //divide k into two parts  
    int pa = min(k / 2, m), pb = k - pa;  
    if (a[pa - 1] < b[pb - 1])  
        return findKth(a + pa, m - pa, b, n, k - pa);  // a的前半部分省略,寻找第k小的数变成寻找第k - pa小的数
    else if (a[pa - 1] > b[pb - 1])  
        return findKth(a, m, b + pb, n - pb, k - pb);  // b的前半部分省略,寻找第k小的数变成寻找第k - pb小的数
    else  
        return a[pa - 1];  
}  

class Solution  
{  
public:  
    double findMedianSortedArrays(int A[], int m, int B[], int n)  
    {  
        int total = m + n;  
        if (total & 0x1)  //表示m+n是奇数
            return findKth(A, m, B, n, total / 2 + 1);  
        else //m+n是偶数 
            return (findKth(A, m, B, n, total / 2)  
            + findKth(A, m, B, n, total / 2 + 1)) / 2;  
    }  
};

 

 

 

posted @ 2014-06-24 17:22  Xylophone  Views(165)  Comments(0Edit  收藏  举报