2021-11-07 寻找两个正序数组的中位数

标签:二分查找

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

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

输入:nums1 = [2], nums2 = []
输出:2.00000

提示:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目理解

先将两个结果集进行并集,然后查找对应的中位数。

中位数分两种情况,如果集合长度为偶数,中位数为中间两位数之和的平均值;如果集合长度为奇数,中位数为中间位数的值。

合并求解

public double findMedianSortedArrays(int[] nums1, int[] nums2) {

    int len1 = nums1.length;
    int len2 = nums2.length;
    int data[] = new int[len1+len2];
    int j = 0 ;
    if(len1==0 && len2==0 ){
        return 0.0;
    }
    if(len1==0 ){
        return count(nums2,len2);
    }
    if( len2==0 ){
        return count(nums1,len1);
    }
    int count = 0;
    if(nums1[0] >=nums2[len2-1] ){

        for (int i = 0; i < len2; i++) {
            data[count++] = nums2[i];
        }
        for (int i = 0; i < len1; i++) {
            data[count++] = nums1[i];
        }
        return count(data,data.length);
    }

    Map<String ,Integer> param =new HashMap<>();
    param.put("count",0);
    param.put("j",0);
    for (int i = 0; i < len1; i++) {
        count = param.get("count");
        j= param.get("j");
        if(j>=len2){
            data[count++] = nums1[i];
            param.put("count",count);
            continue;
        }
        if(nums1[i]<nums2[j]){
            data[count++] = nums1[i];
            param.put("count",count);
        }else{
            data[count++] = nums2[j];
            param.put("count",count);
            j++;
            param.put("j",j);
            if(j>=len2){
                data[count++] = nums1[i];
                param.put("count",count);
                continue;
            }
            iterator(nums1[i],nums2,data,param);
        }
    }
    count = param.get("count");
    j= param.get("j");
    for (int x = j; x < len2; x++) {
        data[count++] = nums2[x];
    }
    return count(data,data.length);
}

private void iterator(int start, int[] nums2, int[] data, Map<String ,Integer> param){
    int j = param.get("j");
    int count = param.get("count");

    if(start<nums2[j]){
        data[count++] = start;
        param.put("count",count);
    }else{
        data[count++] = nums2[j];
        param.put("count",count);
        j++;
        param.put("j",j);
        if(j>=nums2.length){
            data[count++] = start;
            param.put("count",count);
            return ;
        }
        iterator(start,nums2,data,param);
    }
}


/**
 * 计算中位数
 * @param nums
 * @param len
 * @return
 */
private double count(int[] nums,int len){
    if(len==1){
        return nums[0];
    }
    int percent = len%2;
    int middle = len/2;
    if(percent==0){
        return (nums[middle-1]+nums[middle])/2.0D;
    }
    return nums[middle];
}


public static void main(String[] args) {
    FindMedianSortedArraysSolution ss = new FindMedianSortedArraysSolution();
    double result = ss.findMedianSortedArrays(new int[]{1,4,5,6},new int[]{2,3});
    System.out.println(result);
}

二分查找

    /**
     * 定义nums1分割线右侧元素下标为i
     * 定义nums2分割线右侧元素下标为j
     * 从[left,right]之间搜索分割线
     * @param nums1
     * @param nums2
     * @return
     */
    public double findMedianSortedArrays2(int[] nums1, int[] nums2) {
        //为了保证分割线一定在第一个集合中存在,因此保证第一个集合长度大于第二个,防止数组越界
        if(nums1.length>nums2.length ){
            int[] temp= nums1;
            nums1= nums2;
            nums2 = temp;
        }

        int m = nums1.length;
        int n = nums2.length;
        //左侧需要分割的元素个数
        int totalLeft = (m + n + 1) / 2;
        //在nums1中的区间[0,m]中查找分割线
        int left = 0;
        int right = m;

        //要求分割线i左侧的元素 必须小于等于分割线j元素
        //要求分割线j左侧的元素 必须小于等于分割线i元素
        while (left < right) {
            //先取第一个数组偏移量
            int i = left + (right - left + 1) / 2;
            int j = totalLeft - i;
            //不满足上述条件就移动到下一个,如果满足就不调整
            if (nums1[i - 1] > nums2[j]) {
                //搜索下一个区间 [left,i-1]
                right = i - 1;
            } else {
                //不满足条件,第一个数组
                left = i;
            }
        }
        int i = left;
        int j = totalLeft - i;
        int mums1LeftMax = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
        int nums1RightMin = i == m ? Integer.MAX_VALUE : nums1[i];
        int mums2LeftMax = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
        int mums2RightMax = j == n ? Integer.MAX_VALUE : nums2[j];

        if ((m + n) % 2 == 1) {
            return (double) Math.max(mums1LeftMax, mums2LeftMax);
        } else {
            return (Math.max(mums1LeftMax, mums2LeftMax) + Math.min(nums1RightMin, mums2RightMax)) / 2.0D;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值