【算法】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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章