寻找两个正序数组的中位数(C语言)

题目:

        给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

        算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000

示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000

示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000

方法:二分查找

当两个数组总长度为奇数时,中位数表示为第 numsSize/2+1 个元素,当数组长度为偶数时,中位数则为第 numsSize/2 个元素和第 numsSize/2+1 个元素的平均数。因此,我们可以理解这道题是查找第 k 小的数,k 则表示 numsSize/2 或 numsSize/2+1 。

以一个例子来解释一波

A :  1 3 4 9

B :  1 2 3 4 5 6 7 8 9

两数组长度为13,所以 k 为 7,有两个数组,所以我们可以把 k 二分,分别在两个数组里排除缩短时间,最多也只会有 A[0...k/2-1] 和 B[0...k/2-1] 个元素被排除,进而缩小范围,找到答案。(词穷了有点,不知道咋描述,可以看官方解析)

所以,第一次二分,我们需要找到两个数组中下标为 k/2-1=2 的数,即 A[2] ,B[2]

A :  1 3 4 9

B :  1 2 3 4 5 6 7 8 9

显然,A[2] >B[2] ,所以,B[0] 到 B[2] 一定不会是我们要找的第 k 个数,将其排除

同时,更新 k 值,k = k- k/2 =4。

第二次二分,k/2 -1=1, 即 A[1] B[4] 

A :  1 3 4 9

B :  1 2 3 4 5 6 7 8 9

A[1] < B[4] ,同理,排除 A[0] 和 A[1],k = 2

第三次二分,k/2 -1 =0, 即 A[2] B[3]

A :  1 3 4 9

B :  1 2 3 4 5 6 7 8 9

相等了,随意排除一个就可以,假设排除 A

k = k - k/2 =1

k =1 了,这个时候,我们就只需要找两个数组中较小的那个,就是我们要找的第 k 个数。

A :  1 3 4 9

B :  1 2 3 4 5 6 7 8 9

所以,B[3] = 4 就是我们要找的答案。

代码:

int erfen(int *nums1,int *nums2, int nums1Size,int nums2Size, int k){
    int i=0,j=0; //i,j 记住 k/2-1 的老位置,方便下一次改变
    while(true){
        //边界情况,只有一边存在数字,直接返回另一个数组的中值即可
        if(nums1Size==i){
            return nums2[j+k-1];
        }
        if(nums2Size==j){
            return nums1[i+k-1];
        }
        //最后一步就要找到结果了,返回两个值中较小的一个,就是结果
        if(k==1){
            return nums1[i]>nums2[j]?nums2[j]:nums1[i];
        }
        //中间不断判断更新k值的过程
        int newi =(i + k / 2 - 1)>(nums1Size - 1)?nums1Size - 1:(i + k / 2 - 1);
        int newj =(j + k / 2 - 1)>(nums2Size - 1)?nums2Size - 1:(j + k / 2 - 1);
        int pivot1 = nums1[newi];
        int pivot2 = nums2[newj];
        //比较这两个数 
        if (pivot1 <= pivot2) {
            k -= newi - i + 1;
            i = newi + 1;
        }
        else {
            k -= newj - j + 1;
            j = newj + 1;
        }
    }
}
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size){
    int numsSize=nums1Size+nums2Size;
    if(numsSize%2==1){
        return(erfen(nums1,nums2,nums1Size,nums2Size,(numsSize+1)/2));
    }
    else{
        return (erfen(nums1, nums2,nums1Size, nums2Size,numsSize / 2) + erfen(nums1,nums2,nums1Size,nums2Size, numsSize / 2 + 1)) / 2.0;  //PS:2.0很重要,要注意小数
    }
}

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值