求两个有序数组的中位数

leetcode:

4

Median of Two Sorted Arrays    

题目:给两个有序数组,长度为n和m,在 O(log (m+n))时间内找出两个数组中所有数字的中位数。

题解(参考讨论区大佬解法):

递归分治方法,先上代码:

#include <stdio.h>

double findK(int *nums1, int nums1Size, int *nums2, int nums2Size, int k){
    if(!nums1Size) return nums2[k-1];
    if(!nums2Size) return nums1[k-1];
    if(k==1) return nums1[0] < nums2[0] ? nums1[0]:nums2[0];
    if(nums1Size < k/2) return findK(nums1, nums1Size, nums2+k/2, nums2Size-k/2, k-k/2);
    if(nums2Size < k/2) return findK(nums1+k/2, nums1Size-k/2, nums2, nums2Size, k-k/2);
    if(nums1[k/2-1] > nums2[k/2-1]) return findK(nums1, nums1Size, nums2+k/2, nums2Size-k/2, k-k/2);
    if(nums1[k/2-1] < nums2[k/2-1]) return findK(nums1+k/2, nums1Size-k/2, nums2, nums2Size, k-k/2);
    if(k&1) return findK(nums1+k/2, nums1Size-k/2, nums2+k/2, nums2Size-k/2, 1);
    return nums1[k/2-1];
}
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
    int sum = nums1Size + nums2Size;
    if(sum & 1)
        return findK(nums1, nums1Size, nums2, nums2Size, sum/2+1);
    else
        return (findK(nums1, nums1Size, nums2, nums2Size, sum/2)+findK(nums1, nums1Size, nums2, nums2Size, sum/2+1)) / 2.0;
}

int main(){
  int nums1[] = {1};
  int nums2[] = {1};
  double ans = findMedianSortedArrays(nums1, 1, nums2, 1);
  printf("%lf\n", ans);
}

使用findK函数递归寻找第k个数,每次至少去掉1/4~1/2的数据,在剩余的数中继续用同样的方法查找。具体解释:

如果总数是奇数个,那么中位数就是第(sum/2)个数,即findK(sum/2);如果总数是偶数个,那么中位数就是第(sum/2)个数和第(sum/2+1)个数的平均数,即(findK(sum/2)+findK(sum/2+1))/2。

findK函数:

1、如果其中一个数组长度小于2/k,那么第k个数肯定大于另一个数组中前2/k的数,因为第一个数组所有数个数加上第二个数组前k/2数的个数 < k。所以可以将第二个数组中前k/2个数去掉,继续递归寻找;

2、如果两个数组长度都大于2/k,那么比较两个数组中第k/2个数的大小,如果第一个数组中第k/2个数大于第二个数组,则第k个数肯定大于第二个数组中第k/2个数,所以可以将第二个数组前k/2个数去掉,继续递归寻找;

3、如果两个数组第k/2个数相同,那么得看k是奇数还是偶数。

(1)如果k是奇数,那么两个数组都去掉前k/2个数(一共去掉了k-1个数),两个数组中剩余数字中最小的那个就是结果;

(2)如果是偶数,那么这个相同的数字就是总体第k个数字和第k+1个数字,直接返回即可。

 

 

 

 

 

点赞