leetcode_4_median-of-two-sorted-arrays

兩個排序的數組A和B分別含有m和n個數,找到兩個排序數組的中位數,要求時間複雜度應爲O(log (m+n))。

給出數組A = [1,2,3,4,5,6] B = [2,3,4,5],中位數3.5
給出數組A = [1,2,3] B = [4,5],中位數 3
題目鏈接:http://www.lintcode.com/zh-cn/problem/median-of-two-sorted-arrays/#
這道題的難度等級爲困難,難就難在要求時間複雜度爲O(logn),那就不能使用普通的遍歷來做,那樣時間複雜度爲O(n)。
首先在隨機位置將A分成兩部分:
left_A | right_A
A [0],A [1],...,A [i-1] | A [i],A [i + 1],...,A [m-1]
由於A有m個元素,所以有m + 1種切割(i = 0〜m)。其中:left_A.size() = i,right_A.size() = m-i。注意:當i = 0時,left_A爲空,當i = m時,right_A爲空。
同樣,在隨機位置將B切成兩部分:
left_B | right_B
B [0],B [1],...,B [j-1] | B [j],B [j + 1],...,B [n-1]
將left_A和left_B放入一個集合,並將right_A和right_B放入另一個集合。把它們命名爲left_part和right_part:
left_part | right_part
A [0],A [1],...,A [i-1] | A [i],A [i + 1],...,A [m-1]
B [0],B [1],...,B [j-1] | B [j],B [j + 1],...,B [n-1]
如果我們可以確保:
1)left_part.size() == right_part.size()
2)max(left_part)<= min(right_part)
那麼我們將{A,B}中的所有元素劃分爲兩個長度相等的部分,一個部分總是大於另一個部分。然後中值=(max(left_part)+ min(right_part))/ 2。
爲了確保這兩個條件,只需要確保:

(1)i + j == m-i + n-j(或:m-i + n-j + 1)
如果n> = m,我們只需要設置:i = 0〜m,j =(m + n + 1)/ 2-i
(2)B [j-1] <= A [i],A [i-1] <= B [j]
爲什麼一定要n> = m?因爲必須確保j是合法索引,因爲0 <= i <= m和j =(m + n + 1)/ 2-i。如果n <m,則j可以是負數,這將導致錯誤的結果。

在[0,m]中搜索i,找到一個切分點i(j =(m + n + 1)/ 2-i):
使得B [j-1] <= A [i]和A [i-1] <= B[j]。
我們可以按照以下步驟進行搜索:
<1>設置imin = 0,imax = m,然後開始搜索[imin,imax]
<2>設置i =(imin + imax)/ 2,j =(m + n + 1)/ 2-i
<3>現在left_part.size() == right_part.size()。而且只有3種情況:
(1) B[j-1] <= A [i]和A [i-1] <= B [j]
意味着找到了切分點i,停止搜索。
(2) B[j-1]> A [i]
意味着A [i]太小。必須調整i得到B [j-1] <= A [i]。而i只能增加不能減小,因爲當i減小時j將增加,因此,B [j-1]增加並且A [i]減小,永遠不會滿足。所以必須增加i。也就是說,調整搜索範圍爲[i + 1,imax]。因此,imin = i + 1和然後回到第<2>步。
(3) A [i-1]> B [j]
意味着A [i-1]太大,必須減少i得到A [i-1] <= B [j]。因此,設置imax = i-1然後回到第<2>步。
當找到切分點i時,中值爲:
max(A [i-1],B [j-1])(當m + n是奇數時)
或(max(A [i-1],B [j-1])+ min(A [i],B [j]))/ 2(當m + n爲偶數時)

現在考慮邊值i = 0,i = m,j = 0,j = n,即A [i-1],B [j-1],A [i],B [j]有可能不存在的情況。
因爲要確保max(left_part)<= min(right_part)。因此,如果i和j不是邊值(A [i-1],B [j-1]都存在),我們必須檢驗B [j-1] <= A [i],A [i-1] <= B [j]。但是如果A [i-1],B [j-1],A [i],B [j]中的一些不存在,則不需要檢查這兩個條件中對應的一個。例如,如果i = 0,則A [i-1]不存在,則不需要檢查A [i-1] <= B [j]。所以,需要做的是:
在[0,m]中搜索i,找到一個切分點i,使得:
(j == 0或i == m或B [j-1] <= A [i])和
(i == 0或j == n或A [i-1] <= B [j])
其中j =(m + n + 1)/ 2-i
在搜索循環中,只會有三種情況:
(1)(j == 0或i == m或B [j-1] <= A [i])和
(i == 0或j = n或A [i-1] <= B [j])
滿足條件停止搜索。
(2) j> 0和i <m並且B [j-1]> A [i]
i太小,增加i。
(3)i> 0和j <n並且A [i-1]> B [j]
i太大,減少i。
說的比較多,下面是代碼:

class Solution {
public:
    /**
     * @param A: An integer array.
     * @param B: An integer array.
     * @return: a double whose format is *.5 or *.0
     */
    double findMedianSortedArrays(vector<int> A, vector<int> B) {
        //int minidx = 0, maxidx = m, i, j, num1, mid = (m + n + 1) >> 1,num2;
        if (A.size() > B.size()) return findMedianSortedArrays(B,A);
        int m = A.size(),n = B.size();
        int imin = 0,imax = m,half_len = (m + n + 1) / 2,i,j,max_of_left,min_of_right;
        while (imin <= imax) {
            i = (imin + imax) / 2;
            j = half_len - i;
            if (i < m && j > 0 && B[j - 1] > A[i]) imin = i + 1;
            else if (i > 0 && j < n && B[j] < A[i - 1]) imax = i - 1;
            else {
                if (i == 0) max_of_left = B[j - 1];
                else if (j == 0) max_of_left = A[i - 1];
                else max_of_left = max(A[i - 1],B[j - 1]);
                break;
            }
        }
        if ((m + n) % 2 == 1) return max_of_left;
        if (i == m) min_of_right = B[j];
        else if (j == n) min_of_right = A[i];
        else min_of_right = min(A[i],B[j]);
        return (max_of_left + min_of_right) / 2.0;
    }
};


作者:yzawyx0220
鏈接:https://www.jianshu.com/p/7c990b12a82a
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章