力扣每日一题——寻找两个正序数组的中位数

先简单看下问题:

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
在这里插入图片描述
看到该题目,我们大部分人第一反应就是,直接归并排序把nums1和nums2整合为1个数组,然后根据奇偶元素个数取中位数即可。
但是不要忽略了时间复杂度要求 O(log (m+n)) ,如果按照上述的思路,那么我们的时间复杂度为O(m+n)已经超过了以上要求。
所以,看到
log
我们其实可以猜测大概率是使用二分查找,那么我们具体应该如何操作呢?

  • 首先我们计算一下两个数组的长度和totalLen,如果为奇数,我们取其第 totalLen/2 + 1 位的元素就是他的中位数(这里是从1开始数的)。
  • 如果为偶数,我们就取第 totalLen/2 + 1 位的元素,和第totalLen/2位的元素再求中位数。

定义方法getKthElement(int[] nums1, int[] nums2, int k)查找两个数组中第k小的元素

  • 定义nums1和nums2的长度和初始下标。
    在这里插入图片描述
  • 对于一般情况,我们可以的取A[k / 2 - 1] ,B[k / 2 - 1] 的值:
    当A[k / 2 - 1] < B[k / 2 - 1] 时,我们可以确认A[k / 2 - 1] 及之前的元素一定不是第k小的元素,所以将A[k / 2 - 1] 及之前的元素排除, 即 将下标 index1移动至当前A[k /2 - 1]下标 + 1处, k 减去排除的元素个数。
    当B[k / 2 - 1] < A[k / 2 - 1] 时, 我们同样采取以上策略进行,将B[k / 2 - 1]及之前的元素排除。
    当A[k / 2 - 1] == B[k / 2 - 1] 时, 我们可以将其归为上面两种情况之一进行即可。

然后我们要循环到什么时候停止呢,这时候就要想想边界条件时什么了:

  • 当 k == 1时,我们循环停止,因为k代表的就是当前两数组集合中的第k小元素(排除掉之前元素后),这时候我们只要比较两数组当前下标元素的值,更小的元素即为所求。
  • 当index1 == len1时,表面数组nums1已经排除了所有元素,这个适合,我们只要取num2排除之前元素后的第k - 1下标元素即为所求。
  • 当index2 == len2时,表面数组nums2已经排除了所有元素,取num1当前下标往后k - 1的元素。

代码如下:

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int len1 = nums1.length;
        int len2 = nums2.length;
        int totalLen = len1 + len2;
        if (totalLen % 2 == 1){
            return getKthElement(nums1, nums2, totalLen / 2 + 1);
        } else {
            return (getKthElement(nums1, nums2, totalLen / 2 + 1) +
                    getKthElement(nums1, nums2, totalLen / 2)) * 0.5;
        }
    }

    private int getKthElement(int[] nums1, int[] nums2, int k){
        int len1 = nums1.length;
        int len2 = nums2.length;
        int index1 = 0, index2 = 0;
        while (true){
            if (index1 == len1){
                return nums2[index2 + k - 1];
            }
            if (index2 == len2){
                return nums1[index1 + k - 1];
            }
            if (k == 1){
                return Math.min(nums1[index1], nums2[index2]);
            }
            int half = k / 2;
            int newIndex1 = Math.min(index1 + half, len1) - 1;
            int newIndex2 = Math.min(index2 + half, len2) - 1;
            int pivot1 = nums1[newIndex1], pivot2 = nums2[newIndex2];
            if (pivot1 <= pivot2){
                k -= (newIndex1 - index1) + 1;
                index1 = newIndex1 + 1;
            } else {
                k -= (newIndex2 - index2) + 1;
                index2 = newIndex2 + 1;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值