题目大意:在两个已经排好序的数组里面,找出这两个数组的中位数。
解题思路:求两个排好序的数组的中位数,可以用二分法来处理。
如果两个数组的长度(m + n)总和是奇数,则求第(m+n) / 2 + 1大的数
如果两个数组长度(m + n)总和是偶数,则求第(m+n) / 2和第(m+n)/2 + 1这两个数的平均值。
问题可以转换为求这两个已排序数组的第k大的数。
假设这两个数组为A[m]和B[n]
如果A[m/2] 大于等于 B[n/2]
如果 A[0] 到 A[m/2 - 1] 的长度与 B[0] 到 B[n/2]的长度和大于等于k
那么这个第k大的数必然在A[0] 到 A[m/2 - 1] 和B[0] 到 B[n/2]的这两个范围内,
所以A的范围可以缩小为求A[0]到A[m/2 -1] 和B[0]到B[n/2] 这两个数组第k大的数
如果 A[0] 到 A[m/2 - 1] 的长度与 B[0] 到 B[n/2]的长度小于k
那么可以去除B的0~ n/ 2范围的数, 求A的0~m 和 B的n/2 + 1~ n的第k - (n/2 + 1)大的数
如果A[m/2]小于B[n/2],分析的情况只是A与B交换下
范围一直缩小下去。
直到当B的长度为0时,返回A[k]
A的长度为0时,返回B[k]
k为1时,返回当前范围内A和B的首个最小的数。
#include <iostream>
#include <cstdio>
using namespace std;
class Solution {
public:
double findMedianSortedArrays(int A[], int m, int B[], int n) {
if(((m + n) & 1) == 1)
return findKth(A, m, B, n, ((m + n) >> 1) + 1);
else
return (findKth(A, m, B, n, ((m + n) >> 1) + 1) + findKth(A, m, B, n, ((m + n) >> 1))) / 2.0;
}
private:
double findKth(int A[], int m, int B[], int n, int k) {
int median_len = ((m + n) >> 1) + 1;
int A_low = 0, A_high = m - 1;
int B_low = 0, B_high = n - 1;
while(A_low <= A_high && B_low <= B_high && k > 1){
int A_median_index = (A_low + A_high) >> 1;
int B_median_index = (B_low + B_high) >> 1;
int A_median_len = A_median_index - A_low + 1;
int B_median_len = B_median_index - B_low + 1;
if(A[A_median_index] >= B[B_median_index]) {
if(A_median_len + B_median_len - 1 >= k) {
A_high = A_median_index - 1;
} else {
k -= B_median_len;
B_low = B_median_index + 1;
}
} else {
if(A_median_len + B_median_len - 1 >= k) {
B_high = B_median_index -1;
} else {
k -= A_median_len;
A_low = A_median_index + 1;
}
}
}
if(A_low > A_high) {
return B[B_low + k - 1];
} else if(B_low > B_high) {
return A[A_low + k - 1];
} else {
return min(A[A_low], B[B_low]);
}
}
};