【LeetCode】4. Median of Two Sorted Arrays (2 solutions)


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

 

解法一:保底做法,O(m+n)復雜度

按照歸並排序的思路,先歸並,再找中間值。

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size();
        int n = nums2.size();
        vector<int> array = merge(nums1, nums2);
        return ((double)(array[(m+n-1)/2]+array[(m+n)/2]))/2;
    }
    vector<int> merge(vector<int> A, vector<int> B)
    {
        vector<int> ret;
        int m = A.size();
        int n = B.size();
        int i = 0;
        int j = 0;
        while(i < m && j < n)
        {
            if(A[i] <= B[j])
            {
                ret.push_back(A[i]);
                i ++;
            }
            else
            {
                ret.push_back(B[j]);
                j ++;
            }
        }
        if(i == m)
        {
            while(j < n)
            {
                ret.push_back(B[j]);
                j ++;
            }
        }
        if(j == n)
        {
            while(i < m)
            {
                ret.push_back(A[i]);
                i ++;
            }
        }
        return ret;
    }
};

 

解法二:類似二分查找,復雜度O(log(m+n))

這個解法大概思路很簡單,就是A數組的中間元素與B數組的中間元素相比較,從而刪掉較小元素所在數組的前一半和較大元素所在數組的后一半。遞歸下去。

其實要正確實現以上解法還是比較tricky的,因為需要涉及到很多邊界情況,我們來一一解釋:

第一步,我們需要將題目改為尋找第k小的元素findKthSortedArrays。(這里k從1開始計算)

原因在於,如果我們執着於median,那么在刪除一半左右元素形成的子問題中,很難保證仍然是尋找median。可能變為尋找median前一個或者后一個。

(如果仔細思考過這個題就能理解這句話)

改成第k小元素的好處就是,我們可以將刪掉的元素考慮進來,在子問題中不斷改變k的值。

(例如:本來我們需要尋找的median是第5個數,刪掉前面2個數之后,在子問題中就變為尋找第5-2=3個數)

考慮A、B數組總數的奇偶性,就轉化為調用findKthSortedArrays的問題了。

第二部:實現findKthSortedArrays

(一)首先,我們規定A數組比B數組短。

這樣處理的好處在於:我們所需的(k-1)/2位置可能大於某個數組總長度,規定A短之后,只需要考慮超過A的長度,不需要再復制代碼分情況討論了。

這里需要斟酌一下:為什么不是k/2? k/2±1?而是(k-1)/2

我的思考如下:

如果k==1,2,就是需要比較頭兩個元素,因此下標為0

如果k==3,4,就是需要比較第1個元素,因此下標為1

綜上歸納而得。

(二)其次,把特殊情況處理掉。

(1)A數組為空時,即返回B數組第k個元素。

(2)k==1時,即返回A[0]、B[0]中小的那個

(三)接下來再分為兩種情況:

(k-1)/2位置是否超過A數組長度?

(1)若超過,則A數組派出的代表Acandi就是最后元素A[m-1],B派出的代表Bcandi是B[k-m-1]

(a)Acandi==Bcandi,那么正好有k-2個元素比Acandi、Bcandi小,所以第k個元素就是Acandi/Bcandi

(b)Acandi > Bcandi,那么最多只有m-1+k-m-1=k-2個元素比Bcandi小,因此包括Bcandi在內之前的k-m個B數組元素肯定不是第k個數,所以刪去,子問題變為尋找第k-(k-m)個元素

(c)Acandi < Bcandi,那么最多只有m-1+k-m-1=k-2個元素比Acandi小,因此包括Acandi在內之前的整個A數組元素m個元素肯定不是第k個數,所以刪去,子問題變為尋找第k-m個元素

(2)若不超過,則A數組派出的代表Acandi就是A[(k-1)/2],B派出的代表Bcandi是B[(k-1)/2]

(a)Acandi==Bcandi,那么正好有(k-1)/2+(k-1)/2=k-1個元素比Acandi、Bcandi小,所以第k個元素就是Acandi/Bcandi

如果不相等,對於Acandi 、Bcandi本身是否需要取舍就要注意分析了。

經過舉幾個例子簡單分析就很容易發現,k為奇數時,需要保留小的candidate,舍棄大的。

而k為偶數時,需要保留大的candidate,舍棄小的。

(b)Acandi > Bcandi

(b.1)k為奇數,保留Bcandi,刪除Bcandi前面的(k-1)/2個元素,刪除A及A后面的元素(保留A中前(k-1)/2個元素)

(b.2)k為偶數,保留Acandi,刪除Bcandi及前面的(k-1)/2+1個元素,刪除A后面的元素(保留A中前(k-1)/2+1個元素)

(c)Acandi < Bcandi

同(b),略去不贅述了。

class Solution {
public:
    double findKthSortedArrays(int A[], int m, int B[], int n, int k)
    {//k starts from 1
    
        //make sure A is shorter than B
        if(m > n)
            return findKthSortedArrays(B, n, A, m, k);
    
        //special case1: A empty
        if(m == 0)
            return B[k-1];
        //special case2: k==1 (m>0 is guaranteed)
        if(k == 1)
            return min(A[0], B[0]);
        
        int Acandi, Bcandi;
        if((k-1)/2 >= m)
        {//A[(k-1)/2] out of range
            Acandi = A[m-1];
            Bcandi = B[k-m-1];
            if(Acandi == Bcandi)
                return Acandi;
            else if(Acandi > Bcandi) 
            //for A: no skip
            //for B: skip the k-m smaller elements (including Bcandi)
                return findKthSortedArrays(A, m, B+k-m, n-(k-m), k-(k-m));
            else
            //for A: skip the m   smaller elements
            //for B: skip the k-m larger  elements
                return findKthSortedArrays(A+m, 0, B, n-(k-m), k-m);
        }
        else
        {
            //1,2->index0; 3,4->index1; ...
            Acandi = A[(k-1)/2];
            Bcandi = B[(k-1)/2];
            if(Acandi == Bcandi)
                return Acandi;
            else if(Acandi > Bcandi) 
            {
            //for A: skip the larger  elements
            //for B: skip the smaller elements
                if(k%2 == 1)
                //keep the smaller candidate, skip the larger
                    return findKthSortedArrays(A, (k-1)/2, B+(k-1)/2, n-(k-1)/2, k-(k-1)/2);
                else
                //keep the larger candidate, skip the smaller
                    return findKthSortedArrays(A, (k-1)/2+1, B+(k-1)/2+1, n-((k-1)/2+1), k-((k-1)/2+1));
            }
            else
            {
            //for A: skip the smaller elements
            //for B: skip the larger  elements
                if(k%2 == 1)
                //keep the smaller candidate, skip the larger
                    return findKthSortedArrays(A+(k-1)/2, m-(k-1)/2, B, (k-1)/2, k-(k-1)/2);
                else
                //keep the larger candidate, skip the smaller
                    return findKthSortedArrays(A+(k-1)/2+1, m-((k-1)/2+1), B, (k-1)/2+1, k-((k-1)/2+1));
            }
        }
    }
    double findMedianSortedArrays(int A[], int m, int B[], int n) 
    {
        if((m+n)%2 == 0)
        {//average of two medians
            return (findKthSortedArrays(A, m, B, n, (m+n)/2) + findKthSortedArrays(A, m, B, n, (m+n)/2+1))/2;
        }
        else
        {
            return findKthSortedArrays(A, m, B, n, (m+n)/2+1);
        }
    }
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM