二分 - 寻找两个有序数组的中位数 - Leetcode 4
Posted njuptACMcxk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分 - 寻找两个有序数组的中位数 - Leetcode 4相关的知识,希望对你有一定的参考价值。
二分 - 寻找两个有序数组的中位数 - Leetcode 4
给定两个大小分别为 m
和 n
的正序(从小到大)数组 A
和 B
。请你找出并返回这两个正序数组的 中位数 。
示例 1:
输入:A = [1,3], B = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:A = [1,2], B = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:
输入:A = [], B = [1]
输出:1.00000
示例 4:
输入:A = [2], B = []
输出:2.00000
方法一:划分数组( O ( log 2 ( m i n ( n , m ) ) ) O(\\log_2(min(n,m))) O(log2(min(n,m))))
我们可以把两个数组看成是一个数组的两段,然后设法在 A
或者 B
中找出中位数所在的位置。
这个做法需要理解中位数的作用:它把一个数组划分成了等长的两段。
所以,我们首先设法把两个数组重新划分成等长的两段,假设是 left
段 和 right
段,使得 left
段的最大值不超过 right
段的最小值:
left | right
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[n-1]
B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[m-1]
即:
- l e n ( l e f t ) = i + j = l e n ( r i g h t ) = n + m − i − j + [ n + m 是 奇 数 ] len(left)=i+j=len(right)=n+m-i-j+[n+m\\ 是奇数] len(left)=i+j=len(right)=n+m−i−j+[n+m 是奇数]
- max ( l e f t ) ≤ min ( r i g h t ) \\max(left)\\le \\min(right) max(left)≤min(right)
那么答案为:
n + m 为 偶 数 : A n s = max ( l e f t ) + min ( r i g h t ) 2 n+m为偶数:Ans=\\cfrac{\\max(left)+\\min(right)}{2} n+m为偶数:Ans=2max(left)+min(right)
n + m 为 奇 数 : A n s = max ( l e f t ) — — ( 左 边 多 一 个 元 素 ) n+m为奇数:Ans=\\max(left)\\ ——(左边多一个元素) n+m为奇数:Ans=max(left) ——(左边多一个元素)
具体实现细节如下:
- 我们首先要在数组 A 中二分出划分的位置
i
i
i,满足:
max
(
l
e
f
t
)
≤
min
(
r
i
g
h
t
)
\\max(left)\\le \\min(right)
max(left)≤min(right),即:
max ( A [ i − 1 ] , B [ j − 1 ] ) ≤ min ( A [ i ] , B [ j ] ) \\max(A[i-1],B[j-1])\\le \\min(A[i],B[j]) max(A[i−1],B[j−1])≤min(A[i],B[j])
等价于: B [ j − 1 ] ≤ A [ i ] & & A [ i − 1 ] ≤ B [ j ] B[j-1]\\le A[i] \\ \\ \\&\\&\\ \\ A[i-1]\\le B[j] B[j−1]≤A[i] && A[i−1]≤B[j]
我们仔细思考发现,上述条件是满足”单调性的“。因为,我们多分给left
一个元素,就少分给right
一个元素。即, i i i 递增时, j j j 相应地递减,也就是 A [ i ] A[i] A[i] 递增, B [ j ] B[j] B[j] 就递减。那么可以得出结论: A [ i ] A[i] A[i] 越大越好,越容易满足约束条件。
所以,我们可以二分出最大的,满足条件的 A [ i ] A[i] A[i]。 - 注意,根据等长的条件,得到: j = ⌊ m + n + 1 2 ⌋ − i j=\\lfloor{\\cfrac{m+n+1}{2}}\\rfloor-i j=⌊2m+n+1⌋−i,为了保证 j ≥ 0 j\\ge 0 j≥0,简化边界的判断,我们可以假设 m ≤ n m\\le n m≤n,即 A 的长度 ≤ B 的长度。
- 然后我们维护出 max ( l e f t ) \\max(left) max(left) 和 min ( r i g h t ) \\min(right) min(right)。
- 最后根据奇偶性输出答案即可。
代码:
class Solution {
public:
double findMedianSortedArrays(vector<int>& A, vector<int>& B)
{
int m = A.size(), n = B.size();
if(m > n) swap(A, B), swap(m, n);
int l = 0, r = m;
int max_left = 0, min_right = 0;
int A_i, A_im1, B_j, B_jm1;
int i, j;
while(l < r)
{
i = l + r + 1 >> 1;
j = (n + m + 1 >> 1) - i;
// 事实上这里 i > 0 是必然成立的,相对的,j < n 也是必然成立的。
if(A[i - 1] <= B[j]) l = i;
else r = i - 1;
}
j = (n + m + 1 >> 1) - l;
A_i = (l == m ? INT_MAX : A[l]);
A_im1 = (l == 0 ? INT_MIN : A[l - 1]);
B_j = (j == n ? INT_MAX : B[j]);
B_jm1 = (j == 0 ? INT_MIN : B[j - 1]);
max_left = max(A_im1, B_jm1);
min_right = min(A_i, B_j);
return (n + m & 1) ? max_left : (double)(max_left + min_right) / 2.0;
}
};
以上是关于二分 - 寻找两个有序数组的中位数 - Leetcode 4的主要内容,如果未能解决你的问题,请参考以下文章