LeetCode 4 寻找两个正序数组的中位数(困难)

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

进阶:你能设计一个时间复杂度为 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

思路与代码

思路一
双指针(一个指向nums1 一个指向nums2) 按顺序遍历两个数组 找到处于中间位置的数字
时间复杂度 O(m + n)

来自leetcode中评论区代码

public double findMedianSortedArrays(int[] A, int[] B) {
    int m = A.length;
    int n = B.length;
    int len = m + n;
    int left = -1, right = -1;
    int aStart = 0, bStart = 0;
    for (int i = 0; i <= len / 2; i++) {
        left = right;
        if (aStart < m && (bStart >= n || A[aStart] < B[bStart])) {
            right = A[aStart++];
        } else {
            right = B[bStart++];
        }
    }
    if ((len & 1) == 0)
        return (left + right) / 2.0;
    else
        return right;
}

思路二 进阶
时间复杂度 O(log(m+n))
看到log的时间复杂度,我们就知道肯定跟二分有关

1 要确定中位数,我们必须要找到中位的分界线num1Linenum2Line,因为两个数组是分开的,所以每个数组都有各自的分界线。
在这里插入图片描述

2 那么如何找到分界线呢?
我们先确定左边一半的数字大小leftNum,可用两个数组长度的一半来确定。
对其中一个nums1用二分法逼近其分界线,用leftNum - num1Line 来确定数组nums2的分界线num2Line

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if (nums1.length > nums2.length){
        	// 将nums1 设为较小长度的数组
            int[] temp = nums1;
            nums1 = nums2;
            nums2 = temp;
        }

        int m = nums1.length;
        int n = nums2.length;

        int leftNum = (m + n) / 2;  // 左边一半数字的个数
        // 如果 m + n 是偶数 则左边应该有6个数 ,最终结果就是左边一半的最大值加上右边一半的最小值 再除以2
        // 如果 m + n 是奇数 则左边应该有5个数, 最终结果就是右边一半的最小值

        int L = 0, R = m; // L 与 R 来逼近nums1数组的左右一半的分界线

        while (L < R) {
            int i = (L + R + 1) / 2; // i的范围为[1,m] 代表nums1中属于左边一般的数字有i个
            int j = leftNum - i; // 代表nums2中属于左边一半的数字有j个

            if (nums1[i - 1] > nums2[j]) // 如果nums1左边数字的最大值还大于nums2右边数字的最小值
                R--;
            else L++; // 如果nums1左边数字的最大值不大于nums2右边数字的最小值
        }

        int num1Line = L;   // 代表nums1中属于左边一般的数字有num1Line 个
        int num2Line = leftNum - L; // 代表nums2中属于左边一般的数字有num2Line 个

        if ((m + n) % 2 == 0){
            int left = Math.max(
                num1Line == 0 ? Integer.MIN_VALUE : nums1[num1Line-1],
                num2Line == 0 ? Integer.MIN_VALUE : nums2[num2Line-1]
            );
            int right = Math.min(
                num1Line == m ? Integer.MAX_VALUE : nums1[num1Line],
                num2Line == n ? Integer.MAX_VALUE : nums2[num2Line]
            );
            return (left + right + 0.0) / 2;
        }else{
            return Math.min(
                num1Line == m ? Integer.MAX_VALUE : nums1[num1Line],
                num2Line == n ? Integer.MAX_VALUE : nums2[num2Line]
            );
        }

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值