LC4. 寻找两个有序数组的中位数

题目描述

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路
首先,求一个有序数组的中位数,可以取第(length+1)/2和第(length+2)/2位的平均数

其次,我们按照一个例子来整理一下解题的大致思路

假设我们要从两个数组中取出第4位的元素

第一步,从两个数组中分别取第4/2=2位

这样我们得到两个元素,分别是数组1中的3和数组2中的4,但是这样并不能保证我们取到的四个元素就是两个数组中的前4位(比如数组2是【4,6,8,10】),考虑一下这样到底能保证什么呢?其实它可以保证这样一件事情:数组1中的1和3,一定是最终结果中的两位,因为哪怕数组2中4之前的元素都比数组1中的元素要小,数组一中的1和3依然是有身份的~所以现在情况如下图所示

第二步,确定剩下的两位(剩下的K-K/2位,而不是简单的K/2,原因之后会说),而数组1这次可以直接从5开始找,这次是两个数组分别找各自的第1位

显然这次我们又确定了1位,此时情况如下

第三步:此时只剩一位未能确认,这就简单了,从两边分别去最小的,其中的较小的值就是剩下的那一位,而“剩一位未能确认”也是我们的递归边界,这样我们就已经明白整个过程的大体思路了,剩下的一些问题就比较容易理解了

关于之间提到的K-K/2而不是K/2的问题,主要是屏蔽奇偶性带来的一些问题,比如说我们在两个数组中取前5位

K值55/2=22/2=1
每组取的前n位5/2=22/2=1边界
确定位数22+1=22+1+1=4

可见,最终我们只得到了前4位,而如果用K-K/2

 

K值55-5/2=33-3/2=22-2/2=1
每组取的前n位5/2=23/2=12/2=1边界
确定位数22+1=22+1+1=42+1+1+1=5

 

这样我们得到的才是正确结果

class Solution {  
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length,n = nums2.length;
        int l = (m+n+1)/2;
        int r = (m+n+2)/2;
        return (getKth(nums1,0,nums2,0,l)+getKth(nums1,0,nums2,0,r))/2.0;
    }

    private double getKth(int[] nums1, int start1, int[] nums2, int start2, int k) {
        //这里是当一个数组中的元素已经全部有身份了,但是还有空余席位,那就可以直接从另一个数组中取
        if(start1>nums1.length-1) return nums2[start2 + k - 1];
        if(start2>nums2.length-1) return nums1[start1 + k - 1];

        if(k == 1) return Math.min(nums1[start1], nums2[start2]);

        int temp1 = start1+k/2-1<nums1.length?nums1[start1+k/2-1]:Integer.MAX_VALUE;
        int temp2 = start2+k/2-1<nums2.length?nums2[start2+k/2-1]:Integer.MAX_VALUE;

        if(temp1<temp2)
            //注意这个地方是K-k/2,而不是K/2,目的是屏蔽一些奇偶性的问题
            return getKth(nums1, start1 + k / 2, nums2, start2, k-k/2);
        else
            return getKth(nums1,start1,nums2,start2+k/2,k-k/2);
    }
}

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值