每日一题:寻找两个正序数组的中位数(Olog(m+n))

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

示例 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

提示:

  • nums1.length == m
  • nums2.length == n
  • 0 <= m <= 1000
  • 0 <= n <= 1000
  • 1 <= m + n <= 2000
  • -10^6 <= nums1[i], nums2[i] <= 10^6

双指针遍历,时间复杂度O(m+n)

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int n1 = nums1.length;
        int n2 = nums2.length;
        int p1 = 0;
        int p2 = 0;
        int result = 0;
        int last = 0;
        for(int i = 0;i <= (n1 + n2)/2;i++){
            last = result;
            if(p1 < n1 && (p2 >= n2 || nums1[p1] < nums2[p2])){
                result = nums1[p1];
                p1++;
            }else{
                result = nums2[p2];
                p2++;
            }
        }
        if((n1 + n2) % 2 != 0){
            return result;
        }else{
            return (last + result) / 2.0;
        }
    }
}

注意点:

  • 遍历次数。需要保证最后一次遍历得到的就是中位数(长度为奇数情况下),以nums1 = [1,3], nums2 = [2]为例,最后一次遍历要从else分支走出,所以遍历次数为(n1 + n2)/2。
  • 数组越界问题。if的判断从左到右执行,不满足前面的条件就不会走到后面的,所以要把数组下标判断放在前面。
  • 返回值类型。最后要除2.0,如果除2会丢失精度。

二分查找,时间复杂度O(log(m+n))

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int n1 = nums1.length;
        int n2 = nums2.length;
        if((n1 + n2) % 2 != 0){
            return (double)getKth(nums1,nums2,(n1+n2)/2 + 1);
        }else{
            return (getKth(nums1,nums2,(n1+n2)/2) + getKth(nums1,nums2,(n1+n2)/2 + 1))/2.0;
        }
    }

    public int getKth(int[] nums1,int[] nums2,int k){
        int n1 = nums1.length;
        int n2 = nums2.length;
        int p1 = 0;
        int p2 = 0;
        int result = 0;
        while(true){
            if(p1 == n1){
                result = nums2[p2 + k - 1];
                break;
            }
            if(p2 == n2){
                result = nums1[p1 + k - 1];
                break;
            }
            if(k == 1){
                result = Math.min(nums1[p1], nums2[p2]);
                break;
            }
            if(nums1[Math.min(p1 + k/2,n1) - 1] <= nums2[Math.min(p2 + k/2,n2) - 1]){
                int temp = k;
                k -= (Math.min(p1 + k/2,n1) - p1);
                p1 = Math.min(p1 + temp/2,n1);
            }else{
                int temp = k;
                k -= (Math.min(p2 + k/2,n2) - p2);
                p2 = Math.min(p2 + temp/2,n2);
            }
        }
        return result;
    }
}

log级别的时间复杂度一般都要用到二分法。

因为是有序数组,如果确定第i个数不是中位数,那么第0到第i-1个数也不可能是中位数,基于这个原理减少比较次数。

以奇数个数数组为例,中位数是两个有序数组中的第 (m+n)/2 个元素,也即求数组中第(m+n)/2 小的元素。

  • 要找到第 k个元素,可以比较 nums1[k/2−1] 和 nums2[k/2−1]。这两个值前面共有 k/2−1 个元素。对于他们中的较小值,最多有k−2个数比它小,那么它就不可能是第k小的元素。
  • 对于数组越界,需要根据实际排除的个数减少k的大小。
  • 如果一个数组为空,则该数组中的所有元素都被排除,另一个数组中第 k 小的元素即为所求。
  • 当k=1时,说明排除到了中位数的位置,两个数组指针位置的较小值即为中位数。
  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值