zoukankan      html  css  js  c++  java
  • LeetCode Median of Two Sorted Arrays

    Pre-definition: "median of a array" is the right-middle-value element.

    if O(m+n), then Merge Sort is OK!

    Note:  The overall run time complexity should be O(log (m+n)).

    Reaction: Binary-Find!

    Input: A[0...m-1] and B[0...n-1]

    Steps:

    1. get the medians "ma&mb" of array A and B;
    2. compare ma and mb
      • if ma == mb, then return ma/mb;
      • if ma > mb,   then the median lies in the subA[0...|_m/2_|] and subB[|_n/2_|...n-1]
      • if ma < mb,   then the median lies in the subA[|_m/2_|...m-1] and subB[0...|_n/2_|
    3. loop above until subA and subB both have two elements;
    4. then the median = (max(subA[0], subB[0]) + min(subA[1], subB[1])) / 2.

    Assume: the number of elements in A and B are both larger than k/2,

    Then compare the k/2-th smallest element in A(i.e. A[k/2-1]) and the k/2-th smallest element in B(i.e. B[k/2 - 1])

    there are three results:  (Becasue k can be odd or even number, so we assume k is even number here for simplicy. The following is also true when k is an odd number.)

    • if A[k/2-1] = B[k/2-1], we should return one of them
    • A[k/2-1] > B[k/2-1]
    • if A[k/2-1] < B[k/2-1], that means all the elements from A[0] to A[k/2-1](i.e. the k/2 smallest elements in A) are in the range of k smallest elements in the union of A and B. Or, in the other word, A[k/2 - 1] can never be larger than the k-th smalleset element in the union of A and B.


    Why?  We can use a proof by contradiction.

    Since A[k/2 - 1] is larger than the k-th smallest element in the union of A and B, then we assume it is the (k+1)-th smallest one. Since it is smaller than B[k/2 - 1], then B[k/2 - 1] should be at least the (k+2)-th smallest one. So there are at most (k/2-1) elements smaller than A[k/2-1] in A, and at most (k/2 - 1) elements smaller than A[k/2-1] in B.So the total number is k/2+k/2-2, which, no matter when k is odd or even, is surly smaller than k(since A[k/2-1] is the (k+1)-th smallest element). So A[k/2-1] can never larger than the k-th smallest element in the union of A and B if A[k/2-1]<B[k/2-1];
    Since there is such an important conclusion, we can safely drop the first k/2 element in A, which are definitaly smaller than k-th element in the union of A and B. This is also true for the A[k/2-1] > B[k/2-1] condition, which we should drop the elements in B.

    When A[k/2-1] = B[k/2-1], then we have found the k-th smallest element, that is the equal element, we can call it m. There are each (k/2-1) numbers smaller than m in A and B, so m must be the k-th smallest number. So we can call a function recursively, when A[k/2-1] < B[k/2-1], we drop the elements in A, else we drop the elements in B.

    We should also consider the edge case, that is, when should we stop?
    1. When A or B is empty, we return B[k-1]( or A[k-1]), respectively;
    2. When k is 1(when A and B are both not empty), we return the smaller one of A[0] and B[0].


    Attached code:

     1 double findKth(int a[], int m, int b[], int n, int k)
     2 {
     3     //always assume that m is equal or smaller than n
     4     if (m > n)
     5         return findKth(b, n, a, m, k);
     6     if (m == 0)
     7         return b[k - 1];
     8     if (k == 1)
     9         return min(a[0], b[0]);
    10     //divide k into two parts
    11     int pa = min(k / 2, m), pb = k - pa;
    12     if (a[pa - 1] < b[pb - 1])
    13         return findKth(a + pa, m - pa, b, n, k - pa);
    14     else if (a[pa - 1] > b[pb - 1])
    15         return findKth(a, m, b + pb, n - pb, k - pb);
    16     else
    17         return a[pa - 1];
    18 }
    19 
    20 class Solution
    21 {
    22 public:
    23     double findMedianSortedArrays(int A[], int m, int B[], int n)
    24     {
    25         int total = m + n;
    26         if (total & 0x1)
    27             return findKth(A, m, B, n, total / 2 + 1);
    28         else
    29             return (findKth(A, m, B, n, total / 2)
    30                     + findKth(A, m, B, n, total / 2 + 1)) / 2;
    31     }
    32 };

    References:

    http://blog.csdn.net/realxie/article/details/8078043

    http://blog.csdn.net/zxzxy1988/article/details/8587244

    http://www.cnblogs.com/luxiaoxun/archive/2012/09/13/2684054.html

    http://blog.sina.com.cn/s/blog_89b8586f01019x1t.html

    A more general version:

    Find the Kth element of two sorted arrays A[] and B[].

    #include <iostream>  
    #include <string.h>  
    #include <stdlib.h>  
    using namespace std;  
     
    //Notice : K > 0  
    int FindKthElm(int A[], int aBeg, int aEnd, int B[], int bBeg, int bEnd, int k)  
    {  
        if (aBeg > aEnd)  
        {  
            return B[bBeg + k - 1];  
        }  
        if (bBeg > bEnd)  
        {  
            return A[aBeg + k - 1];  
        }  
          
        //取中间位置  
        int aMid = aBeg + (aEnd - aBeg)/2;    
        int bMid = bBeg + (bEnd - bBeg)/2;  
          
        //从A和B的开始位置到两个数组中间位置的元素个数  
        int halfLen = aMid - aBeg + bMid - bBeg + 2;  
          
        if (A[aMid] < B[bMid])  
        {  
            if (halfLen > k)  
            {  
                // 此时在合并的数组中A[aBeg...aMid]和元素一定在B[bMid]的左侧,  
                // 即此时第k大的元素一定比B[bMid]这个元素小(严格来说不大于)  
                // 故以后没有必要搜索 B[bMid...bEnd]这些元素  
                return FindKthElm(A, aBeg, aEnd, B, bBeg, bMid - 1, k);  
            }  
            else  
            {  
                // 此时在合并的数组中A[aBeg...aMid]元素一定在B[bMid]的左侧,  
                // 所以前K个元素中一定包含A[aBeg...aMid](可以使用反证法来证明这点)  
                // 但是无法判断A[amid+1...aEnd]与B[bBeg...bEnd]之间的关系,对他们进行判断  
                // 此时K就剩下除去A[aBeg...aMid]这些元素,个数为k - (aMid - aBeg + 1)  
                return FindKthElm(A, aMid + 1, aEnd, B, bBeg, bEnd, k - (aMid - aBeg + 1));  
            }  
        }  
        else  
        {  
            //注释与上面相似  
            if (halfLen > k)  
            {  
                return FindKthElm(A, aBeg, aMid - 1, B, bBeg, bEnd, k);  
            }  
            else  
            {  
                return FindKthElm(A, aBeg, aEnd, B, bMid + 1, bEnd, k - (bMid - bBeg + 1));  
            }  
        }  
    }  
      
      
    int main()  
    {  
        const int ALen = 11;  
        const int BLen = 5;  
         
        int apos = 0;  
        int bpos = 0;  
        int A[ALen];  
        int B[ALen];  
          
       //生成两个递增数组A 和 B  
      for (int i = 1; i <= ALen + BLen; ++i)  
       {  
            if (apos >= ALen)  
          {  
               B[bpos++] = i;  
           }  
           else if (bpos >= BLen)  
            {  
               A[apos++] = i;  
           }  
           else  
            {  
                if (rand()%2 == 1)  
                {  
                    A[apos++] = i;  
                }  
                else  
                {  
                    B[bpos++] = i;  
                }  
            }  
        }  
          
        //输出A和B的内容  
        for (int i = 0; i < ALen; ++i)  
        {  
            cout <<A[i] <<" ";  
        }  
        cout <<endl;  
        for (int i = 0; i < BLen; ++i)  
        {  
            cout <<B[i] <<" ";  
        }  
        cout <<endl;  
          
        //验证每个K是不是正解  
        for (int i = 1; i <= ALen + BLen; ++i)  
        {  
            cout << i <<" : "<<FindKthElm(A, 0 , ALen - 1, B, 0 , BLen - 1, i)<<endl;  
        }  
          
        return 0;  
    }
  • 相关阅读:
    LeetCode--414--第三大的数
    LeetCode--412--Fizz Buzz
    LeetCode--409--最长回文串
    《Cracking the Coding Interview》——第18章:难题——题目6
    《Cracking the Coding Interview》——第18章:难题——题目5
    《Cracking the Coding Interview》——第18章:难题——题目4
    《Cracking the Coding Interview》——第18章:难题——题目3
    《Cracking the Coding Interview》——第18章:难题——题目2
    《Cracking the Coding Interview》——第18章:难题——题目1
    《Cracking the Coding Interview》——第17章:普通题——题目14
  • 原文地址:https://www.cnblogs.com/CathyGao/p/3055302.html
Copyright © 2011-2022 走看看