【算法】LeetCode 4 - Median of Two Sorted Arrays

2019.10.20

文章目錄

思路

首先,擴展到一般情況有助於求解此題,假設我們要求解的是兩個有序序列的第k個元素。
然後,對於log(m+n)時間複雜度的要求,不難想到,採用二分法的思想,可以達到O(logn)級複雜度。具體推導此處略。

A[0, 1, ..., i, ..., m)  B[0, 1, ..., j, ..., n)
C[0, 1, ..., k-1, ..., m+n)

兩個數組A、B是有序序列,假設AB歸併排序後變成有序數組C,那麼一定存在i∈[0,m), j∈[0,n),使得A[0, i]∪B[0, j]集合的個數爲k個,且A[i] <= B[j+1] && B[j] <= A[i+1],即A[0, i]∪B[0, j]的k個元素是C中最小的k個元素,那麼C的第k個元素C[k-1] = max{A[i], B[j]}

原理

原理大概總結如下:如思路中所說,我們的目標是找到符合條件的i, j,但A[i] <= B[j+1] && B[j] <= A[i+1]不容易滿足;一旦不滿足,我們可採用二分法思想縮小查找範圍,直到找到爲止。具體說明如下:

left           right
A[0, i]  |  A[i+1, m)
B[0, j]  |  B[j+1, n)

爲了簡化求解,我們令i = j,即i = j = k / 2 - 1(注意k的最小值是1);且m <= n。

  1. A[i] <= B[j+1] && B[j] <= A[i+1],即max{left} <= min{right},此時第k個元素爲:
C[k] = max{A[i], A[j]} (k爲偶數)
     = min{A[i+1], A[j+1]}(k爲奇數)
  1. A[i+1] < B[j],即A[i] <= B[j],可排除A[0, i],因爲第k個元素一定不在A[0, i]中:
反證法:
假設第k個元素在A[0, i]中,即C[k-1] = A[i'],0<= i' <= i
那麼,就必須在B數組中找到 k - i' 個元素,即 k / 2 + 1 個元素
使得,B[j'](0<= j' < k-i')都小於A[i']
然而,A[i] <= B[j],B中最多隻有j個元素,即 k / 2 - 1 個元素可能小於A[i']
矛盾
因此,第k個元素一定不在B[0, j]中
  1. B[j+1] < A[i],即B[j] <= A[i],同理可證,第k個元素一定不在B[0, j]中。
  2. 我們再討論一下邊界條件,上面成立的條件是0 <= k/2 - 1 < m <= n
    4.1 k/2 - 1 < 0,即k<2 -> k = 1時,顯然第k個元素爲min{A[0], B[0]}
    4.2 k/2 - 1 >= m,即A[0, m)無法繼續被拆分成兩個部分,那麼可排除B[0, j]
反證法:
假設第k個元素在B[0, j]中,即C[k-1] = A[j'],0<= j' <= j
那麼,就必須在A數組中找到 k - j' 個元素,即 k / 2 + 1 個元素
使得,A[i'](0<= i' < k-j')都小於B[j']
然而,m <= k/2 - 1
矛盾
因此,第k個元素一定不在B[0, j]中

代碼

public double func(int[] foo, int[] bar) {
    int size = foo.length + bar.length;
    return ( iter(foo, 0, bar, 0, (size + 1)/2),
             iter(foo, 0, bar, 0, (size + 2)/2) )/(double)2;
}
public static int iter(int[] foo, int s1, int[] bar, int s2) {
    if (s1 >= foo.length) return bar[s2 + k - 1];
    if (s2 >= bar.length) return foo[s1 + k - 1];
    if (k == 1) return Math.min(foo[s1], bar[s2]);
    
    int step = k/2;
    int i = s1 + step - 1;
    int j = s2 + step - 1;
    int fooMid = i < foo.length ? foo[i] : Integer.MAX_VALUE;
    int barMid = j < bar.length ? bar[j] : Integer.MAX_VALUE;
    if (fooMid < barMid) {
        return iter(foo, s1 + step, bar, s2, k - step);
    } else {
        return iter(foo, s1, bar, s2 + step, k - step);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章