题意:
给定长度为 n n n的数组 A A A和长度为 m m m的数组 B B B,均为正序数组,请你求出这两个数组中所有元素的中位数。
要求: O ( log ( n + m ) ) O(\log (n+m)) O(log(n+m))的时间复杂度
题解:
两个数组正序合并和得到数组 c c c
那么中位数是数组 c c c的第 ⌊ n + m + 1 2 ⌋ \lfloor\frac{n+m+1}{2}\rfloor ⌊2n+m+1⌋和第 ⌊ n + m + 2 2 ⌋ \lfloor\frac{n+m+2}{2}\rfloor ⌊2n+m+2⌋个数的平均值
这里解释下为什么是求数组 c c c的第 ⌊ n + m + 1 2 ⌋ \lfloor\frac{n+m+1}{2}\rfloor ⌊2n+m+1⌋和第 ⌊ n + m + 2 2 ⌋ \lfloor\frac{n+m+2}{2}\rfloor ⌊2n+m+2⌋: l e n = n + m len=n+m len=n+m
- 当 l e n len len为奇数,奇数的中位数就是第 ⌊ l e n + 1 2 ⌋ \lfloor\frac{len+1}{2}\rfloor ⌊2len+1⌋个数,显然 ⌊ l e n + 1 2 ⌋ = ⌊ l e n + 2 2 ⌋ \lfloor\frac{len+1}{2}\rfloor=\lfloor\frac{len+2}{2}\rfloor ⌊2len+1⌋=⌊2len+2⌋
- 当 l e n len len为偶数,偶数的中位数是第 ⌊ l e n 2 ⌋ \lfloor\frac{len}{2}\rfloor ⌊2len⌋和第 ⌊ l e n 2 ⌋ + 1 ( \lfloor\frac{len}{2}\rfloor+1( ⌊2len⌋+1(即 ⌊ l e n + 2 2 ⌋ ) \lfloor\frac{len+2}{2}\rfloor) ⌊2len+2⌋)个数的平均值。
所以问题转换为:求两个正序数组的第 k k k大数
考虑分治来求:
答案可能是两个数组的第 k k k个,然后拿出一半 h a l f = ⌊ k 2 ⌋ half=\lfloor\frac{k}{2}\rfloor half=⌊2k⌋比较,如果 A A A数组当前的中间部分小于 B B B数组的中间部分,那么 A A A的左半部分必然不会成为答案,这样也增加了小于 k k k的部分的数量,所以整体的可能答案长度也减少为 k − h a l f k-half k−half。
注意两个边界(出口):
- 若可能答案长度已经超过数组 A A A的最大索引,则答案只会在 B B B中,反之亦然。
- 若可能答案长度为 1 1 1,那么可以直接比较两者
代码:
class Solution {
public:
double dfs(vector<int>& A, vector<int>& B, int stA, int stB, int k) {
if(stA >= A.size()) return B[stB + k - 1];
if(stB >= B.size()) return A[stA + k - 1];
if(k == 1) return min(A[stA], B[stB]);
int half = k / 2;
int vA = stA + half - 1 < A.size() ? A[stA + half - 1] : INT_MAX;
int vB = stB + half - 1 < B.size() ? B[stB + half - 1] : INT_MAX;
if(vA < vB) return dfs(A, B, stA + half, stB, k - half);
else return dfs(A, B, stA, stB + half, k - half);
}
double findMedianSortedArrays(vector<int>& A, vector<int>& B) {
int len = A.size() + B.size();
return dfs(A, B, 0, 0, (len + 1) / 2) * 0.5 + dfs(A, B, 0, 0, (len + 2) / 2) * 0.5;
}
};