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

题目描述:

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

算法的时间复杂度应该为 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

提示:

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

思路分析一:合并数组

        1、将两个数组合并为一个数组(开辟新数组),再对这个合并后的数组进行排序。

        2、输出新数组的中位数。若为奇数,则直接输出;若为偶数,则输出中间两个数的平均数。

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int sum = nums1.length+nums2.length;
        int[] arrs = new int[sum];
        System.arraycopy(nums1,0,arrs,0,nums1.length);
        System.arraycopy(nums2,0,arrs,nums1.length,nums2.length);
        Arrays.sort(arrs);

        if(sum % 2 == 1){
            int index = (sum-1)/2;
            return arrs[index];
        }else{
            return (double)(arrs[sum/2]+arrs[sum/2-1])/2;
        }
    }
}

当然,最后判断的条件也可以用 三目运算符 简化为如下:

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int sum = nums1.length+nums2.length;
        int[] arrs = new int[sum];
        System.arraycopy(nums1,0,arrs,0,nums1.length);
        System.arraycopy(nums2,0,arrs,nums1.length,nums2.length);
        Arrays.sort(arrs);


        return sum % 2 == 1 ? arrs[(sum-1)/2] :  (double)(arrs[sum/2]+arrs[sum/2-1])/2;
    }
}

这种方式简单粗暴,但是由于需要新建数组,时间复杂度高。

思路分析二:双指针判定

        1、情况1:有一个数组为空。

当数组a为空时,直接对数组b进行判定。

b数组为奇数个,输出中间数b.length/2

b数组为偶数个,输出 (b[b.length/2 - 1] + b[b.length/2]) /2

注意:由于nums1/nums2数组为int类型的数组,在做除法运算时需要注意类型的转换,'/2.0',或者进行强制类型转换。

        2、情况2:两个数组都为非空数组

        定义两个指针[min1]和[min2],分别指向 数组nums1 和 数组nums2 的首位。由于nums1和nums2是由小到大有序排列的,所以只需要判定两个指针指向的数字。

        当nums1[min1]<nums2[min2]时,min1++,同时计数count++。

        当计数count到达nums1+nums2的中间时,停止进行判断。所以我们需要对nums1+nums2进行判断其为奇数还是偶数。

        详细的解释放在下面代码中逐行进行注释。

public class likou004 {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        // 用指针的方法循环判定
        int min1 = 0, min2 = 0;
        int max1 = nums1.length, max2 = nums2.length;

        // 如果其中一个数组为空,则直接返回另一个数组的中间数
        if(max1==0) return max2%2==0?(nums2[max2/2-1]+nums2[max2/2])/2.0:nums2[(max2-1)/2];
        if(max2==0) return max1%2==0?(nums1[max1/2-1]+nums1[max1/2])/2.0:nums1[(max1-1)/2];

        // 当两个数组都为非空时,采用双指针求解。
        // 定义两个指针,分别指向nums1和nums2的首位,比较nums1和nums2的大小
        // 定义一个计数,当 计数=(num1+num2)/2 时,当前指针指向的位置即为中位数
        // 需要对nums1和nums2进行奇数偶数判定。
        // 偶数:(nums1[指针1] + nums2[指针2]) / 2
        // 奇数:当前指针位置

        int count = 0;     // 计数
        double ans = 0;    // 当前指针指向的值,用于返回

        // 先进行偶数判定
        if((max1+max2) %2 == 0){
            while(count < (max1+max2)/2){
                // 若其中一个数组已经遍历完成,则对另一个数组的指针进行移位操作。
                if(min1==max1){
                    ans = nums2[min2++];
                }
                if(min2==max2){
                    ans = nums1[min1++];
                }

                // 若nums1[指针1] < nums2[指针2]
                // 由于是从小到大排序,故当前值ans赋值nums1[指针1]
                // 赋值结束,指针1向右移1位
                if(min1<max1 && min2<max2){
                    ans = nums1[min1]<nums2[min2] ? nums1[min1++] : nums2[min2++];
                }

                // 每循环1次,计数+1
                count++;
            }

            // 当其中一个数组遍历结束时,ans为另一个数组的两位数之和
            if(min1==max1) return (ans+nums2[min2])/2.0;
            if(min2==max2) return (ans+nums1[min1])/2.0;

            // 中间值在两个数组之间时的取值方式
            // 当前ans为两个中位数中较小的那个
            // 通过nums1[指针1]和nums2[指针2]进行大小判定,小的那个即为下一位中位数
            return nums1[min1]<nums2[min2] ? (ans+nums1[min1])/2.0 : (ans+nums2[min2])/2.0;



            // 数组为奇数时
        }else {
            while(count <= (max1+max2)/2){
                if(min1==max1){
                    ans = nums2[min2++];
                }
                if(min2==max2){
                    ans = nums1[min1++];
                }
                if(min1<max1 && min2<max2){
                    ans = nums1[min1]<nums2[min2] ? nums1[min1++] : nums2[min2++];
                }
                count++;
            }
            return ans;

        }

    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值