There are two sorted arrays
nums1
and
nums2
of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
该方法的核心是将原问题转变成一个寻找第k小数的问题(假设两个原序列升序排列),这样中位数实际上是第(m+n)/2小的数。所以只要解决了第k小数的问题,原问题也得以解决。
首先假设数组A和B的元素个数都大于k/2,我们比较A[k/2-1]和B[k/2-1]两个元素,这两个元素分别表示A的第k/2小的元素和B的第k/2小的元素。这两个元素比较共有三种情况:>、<和=。如果A[k/2-1]<B[k/2-1],这表示A[0]到A[k/2-1]的元素都在A和B合并之后的前k小的元素中。换句话说,A[k/2-1]不可能大于两数组合并之后的第k小值,所以我们可以将其抛弃。
class Solution {
public:
#define Iter vector<int>::iterator
double findKthNum(Iter begin1, Iter end1, Iter begin2, Iter end2, int k){
//保持较小的数组在前面
if(end1 - begin1 > end2 - begin2){
return findKthNum(begin2, end2, begin1, end1, k);
}
//如果前面较小的数组为空了,则返回第二个数组里的第K个值
if(end1 - begin1 == 0){
return *(begin2 + k -1);
}
//此时k为1了(因为前面把数组小的放在前面,而且数组小的那个为空的特殊情况,上面已经处理,所以可以放心使用begin1)
if(k == 1){
return min(*begin1, *begin2);
}
/*因为是第K个数,所以在比较以及取值的时候一定要 -1 */
int m = end1 - begin1, n = end2 - begin2;
int part1 = min(m, k/2), part2 = k - part1;
if(*(begin1 + part1 - 1) < *(begin2 + part2 - 1)){
//在这个情况下,即使二个数组合并后,第一个数组的part1个也在合并的前面,去掉
return findKthNum(begin1 + part1, end1, begin2, end2, k - part1);
}else if(*(begin1 + part1 - 1) > *(begin2 + part2 - 1)){
return findKthNum(begin1, end1, begin2 + part2, end2, k - part2);
}else{
return *(begin1 + part1 - 1);
}
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
Iter begin1 = nums1.begin(), end1 = nums1.end();
Iter begin2 = nums2.begin(), end2 = nums2.end();
int m = nums1.size(), n = nums2.size();
int one_result = findKthNum(begin1, end1, begin2, end2, (m+n)/2 + 1);
if((m + n) & 0x1 == 1){
return one_result;
}
return (one_result + findKthNum(begin1, end1, begin2, end2, (m+n)/2)) / 2.0;
}
};