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

给定两个大小为 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

详解:

从有序数组找出中位数,那什么是中位数呢?

我们在衡量一组数据的时候,一般都根据平均数衡量(所有数的和除以数的个数)

但是有些场景,比如考完试需要衡量一个班的水平。

假如此次考试A班11个人,其中10个考了100,99,98,97,96,95,94,93,92,91,还有一个1个考了个0,那平均数是多少呢?86.8分。

还有B班也是11个人,他们都是考了86分。

这个时候哪个班强一些呢?实际感官肯定是A班,只是因为有个老鼠屎,才拉低了平均数,这个时候中位数就可能更好的衡量了。

将一个班的分数排名之后,处于最中间的分数即为中位数,也就是A班中位数95,B班还是86。

好了不多说了,回归题目。

可以简单思考发现:

当个数n为奇数的时候,中位数就是第n/2 + 1位置的数

当个数n为偶数的时候,中位数就是第n/2和n/2 + 1位置的数的平均值

那这很明显的可以看出来,这个题目是叫求第n/2和第n/2+1的数了

那自然延伸到两个有序数组求第K大的数

int findKthSmallestNum(int[] nums1, int start1, int[] nums2, int start2, int k)

当start1大于nums1的长度,那第K大就是nums2里面的第K大

当start2大于nums2的长度,那第K大就是nums1里面的第K大

为了求第K大,可以判断nums1和nums2的前面第k/2大的数(下面会讲为什么),也就是x = nums1[start1 + k / 2]和y = nums2[start2 + k / 2]的大小.

x和y的较小者(假如为x)可以断定第k大的数一定不在x所在数组的前k/2个数中,因为这两数组分出的这两段数刚好K个,第K大的如果在这里面那也一定是x和y的较大者y。但是这个较大者y不一定是这个方法的结果,因为这个第K大的数还有可能在x所在数组的后面,只是能确定第k大的数一定不在x所在数组的前k/2个数中

那么问题规模可以缩小到k的一半,直到k等于1(此时可以直接通过比较得出结果)

再详细的思路也不及代码片行,那直接贴代码:

    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int L = nums1.length + nums2.length;
        int middleIndex = (L + 1) >> 1;
        int middle = findKthSmallestNum(nums1, 0, nums2, 0, middleIndex);
        if((L & 1) == 1){
            return middle;
        }else{
            return (middle + findKthSmallestNum(nums1, 0, nums2, 0, middleIndex + 1)) / 2.0;
        }
    }
    
    public int findKthSmallestNum(int[] nums1, int start1, int[] nums2, int start2, int k){
        if(start1>= nums1.length){
            return nums2[start2 + k -1];
        }
        if(start2 >= nums2.length){
            return nums1[start1 + k -1];
        }
        if(k == 1){
            return getMin(nums1[start1], nums2[start2]);
        }
        int middle = k >> 1;
        if(start1 + middle > nums1.length){
            return findKthSmallestNum(nums1, start1, nums2, start2 + middle, k - middle);
        }else if(start2 + middle > nums2.length){
            return findKthSmallestNum(nums1, start1 + middle, nums2, start2, k - middle);
        }else if(nums1[start1 - 1 + middle] < nums2[start2 - 1 + middle]){
            return findKthSmallestNum(nums1, start1 + middle, nums2, start2, k - middle);
        }else{
            return findKthSmallestNum(nums1, start1, nums2, start2 + middle, k - middle);
        }
    }

    public int getMin(int a, int b){
        return a < b ? a : b;
    }

最后贴效率:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值