力扣:寻找两个正序数组的中位数

题目描述:

给定两个大小分别为 m 和 n 的正序(从小到大)数组 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

示例 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

第一种:暴力合并两个有序数组(归并),再过程中判断中位数

思路:

开辟一个新的数组help,长度为两个数组的长度和。使用两个指针分别指向两个数组的开头,比较两个指针所指的元素,将比较小的元素放入到新的数组中。之后继续上述的操作,直到将所有的数都放入到help中。实现很简单。代码如下

代码

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int length = nums1.length + nums2.length;
        double result = 0;
        //分别进行奇数偶数处理
        if(length % 2 != 0){//奇数
            result = getNum(nums1,nums2,length/2);
        }else{//偶数
            result = getNum(nums1,nums2,length/2-1)/2 + getNum(nums1,nums2,length/2)/2;
        }
        return result;
    }

    public double getNum(int[] nums1, int[] nums2, int k){
        int[] result = new int[nums1.length+nums2.length];
        int i = 0, j = 0;
        int cur = 0;
        while(i < nums1.length && j <nums2.length && cur <= k){
            if(nums1[i] < nums2[j]) result[cur++] = nums1[i++];
            else result[cur++] = nums2[j++];
        }
        while(i < nums1.length && cur <=k) result[cur++] = nums1[i++];
        while(j < nums2.length && cur <=k) result[cur++] = nums2[j++];
        return result[cur-1];
    }
}

归并的时间复杂度与空间复杂度都是线性复杂度O(m+n)。并不符合你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?这种我们首先想到二分查找。

第二种:确定中间分割线的二分查找

思路:

因为我们的两个数组都是有序的,那么一定有一种可以将两个数组看作一个数组,但是又不用合并数组的方法。我们可以想象有一条线将两个数组的元素分割开来:

类似下面这种:将左右两部分割为元素个数大概相等的两部分:

比如上面的数组为arr1,分割线右边的第一个角标为x;

第二个数组为arr2,分割线右边的第一个角标为y

需要满足arr1[x-1]<=arr2[y]&&arr[y-1]<=arr[x]

如果两个数组的长度和为偶数时:中位数取决于分割线左右两边的四个数

如果两个数组长度和为奇数时:中位数取决于分割线左边的两个数。

我们的主要任务就是确认分割线的位置,这还可以简化为确定分割线在arr1中的位置:即x的值,因为只要x确定,那么y的值也就确定了,分割线需要满足arr1[x-1]<=arr2[y]&&arr[y-1]<=arr[x]

并且x+y = (arr1.length+arr2.length+1)/2(我们默认如果长度和为奇数的话,让左边的元素个数多一个)

代码

class Solution {
    public double findMedianSortedArrays(int[] arr1, int[] arr2) {
        if(arr1.length>arr2.length){
            //交换,符合第一个是较短的
            int swap [] = arr2;
            arr2 = arr1;
            arr1=swap;
        }
        int len1 = arr1.length;
        int len2 = arr2.length;

        //左边的元素个数
        int leftTotalNum = (len1+len2+1)/2;
        int left=0;//二分查找的左边界(一开始的时候)
        int right = len1;//二分查找的右边界(一开始的时候)
        //二分查找
        while(left<right){
            int i= left +(right - left +1)/2 ;//从中间位置开始
            int j = leftTotalNum-i;//arr2的中位线角标位置
            if(arr1[i-1]>arr2[j]){
                //下一轮搜索
                right = i-1;//收缩右边的空间继续查找
            }else
            {
                left = i;//收缩左边的空间继续查找
            }

        }
        int i = left;//此时left为arr1中位线的右边的第一个角标
        int j = leftTotalNum -i;
        int arr1LeftMax = (i==0)?Integer.MIN_VALUE:arr1[i-1];
        int arr1RightMin = (i==len1)?Integer.MAX_VALUE:arr1[i];
        int arr2LeftMax = (j==0)?Integer.MIN_VALUE:arr2[j-1];
        int arr2RightMin = (j==len2)?Integer.MAX_VALUE:arr2[j];

        if((len1+len2)%2 == 1){//总数为奇数,则返回左边最大的
            return Math.max(arr1LeftMax,arr2LeftMax);
        }else{//总数是偶数,则返回 (leftMax+rightMin)/2
            return ((double) Math.max(arr1LeftMax,arr2LeftMax)+Math.min(arr1RightMin,arr2RightMin))/2;
        }

    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值