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。
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为奇数)
- 若
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]中
- 若
B[j+1] < A[i]
,即B[j] <= A[i]
,同理可证,第k个元素一定不在B[0, j]
中。 - 我们再讨论一下边界条件,上面成立的条件是
0 <= k/2 - 1 < m <= n
:
4.1k/2 - 1 < 0
,即k<2 -> k = 1
时,显然第k个元素为min{A[0], B[0]}
;
4.2k/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);
}
}