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

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

思路:我们只关注从nums1中取多了、取少了、或者刚刚好。 假设 nums1 中有 n 个元素,我们二分的取[1,n]个元素,取0个元素作为边界情况特殊处理

变量名约定:

变量名描述
leftPartSize左部分个数: 中位数及其左边元素个数
totalSize元素总个数
num1从nums1中取 num1个元素
num2从nums2中取 num2 个元素
  • leftPartSize = totalSize / 2 +1(奇偶数都正确)
  • num1+num2 = leftPartSize (奇偶数都正确)
  • totalSize,leftPartSize是固定的

已知 totalSize(nums1.len+nums2.len),可以求出 leftPartSize。剩下的就是确定 num1和num2。我们在区间[1,nums1.length] 二分的查找num1,通过 num2 = leftPartSize -num1 计算出 num2,然后判断 num1取的是否合适,取多了,还是少了

变量名讲解

  • 单数组为例

    image-20210223114030767

  • 双数组边界情况 左部分全在一个数组中

    image-20210223114142228

  • 双数组一般情况

    image-20210223113948244

边界情况分析 以只取 num1 为例

中位数及其左边的元素个数为 leftPartSize,如果只取num1则应该满足:

  • nums2为空数组

    image-20210223115602651

  • nums1的长度大于 leftPartSize,并且 nums1的第leftPartSize个元素的是小于等于nums2第一个元素

image-20210223115922172

其代码如下:

public boolean borderCase(int[] ary,int[] otherAry,int leftPartSize){
    // 只在num1中取
    if(otherAry.length==0||ary.length>=leftPartSize && ary[leftPartSize-1]<=otherAry[0]){
        return true;
    }
    return false;
}

明确二分流程

我们在区间[1,nums1.len]二分查找合适的 num1使其满足 nums1[num1-1]nums2[num2-1]是候选中位数。

left = 1;
right = nums1.length+1;
while(left<right){
    num1 = (left+right)/2;
    if(num1刚好合适){
        return 中位数
    }
    else if(num1取少了){
        left = num1+1;
    }
    else{
        right = num1;
    }
}

num1取得刚好合适

如果num1选取正合适,那么 nums1[num1-1]nums2[num2-1]都是左部分,一定小于右部分的最小的元素

Math.max(nums1[num1-1], nums2[num2-1])<=Math.min(nums1[num1],nums2[num2]);

考虑 num2 边界情况

Math.max(nums1[num1-1], nums2[num2-1])<=Math.min(num1!=nums1.length?nums1[num1]:Integer.MAX_VALUE,num2!=nums2.length?nums2[num2]:Integer.MAX_VALUE)

nums1取多了

nums1取多了,导致 num1 增大,nums[num1-1]也增加,我们只需判断 nums1[num1-1]>nums2[num2-1]就好了

程序流程

  public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int totalSize = nums1.length+nums2.length;
        int leftPartSize = totalSize/2+1;
        boolean edgeFlag;
        boolean isEven;

        // 边界情况 左部分只在nums1中
        if(borderCase(nums1,nums2,leftPartSize)){
            // 获取边界情况的解
            return getBorderSolution(nums1,leftPartSize,totalSize);
        }
        // 边界情况 左部分只在nums2中
        if(borderCase(nums2,nums1,leftPartSize)){
            // 获取边界情况的解
            return getBorderSolution(nums2,leftPartSize,totalSize);
        }

        // 进入正常情况
        return normalCase(nums1,nums2,leftPartSize,totalSize);
    }

public double normalCase(int[] nums1, int[] nums2, int leftPartSize,int totalSize){
    left = 1;
    right = nums1.length+1;
    while(left<right){
        num1 = (left+right)/2;
        num2 = leftPartSize - num1;
        
        // num2是否越界检测 ...
       
        if(num1刚好合适){
            return 中位数
        }
        else if(num1取少了){
            left = num1+1;
        }
        else{
            right = num1;
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值