每日一题:寻找两个正序数组的中位数

170 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

题目链接

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

解题思路:(合并数组排序+二分查找)

  • 遍历两个数组,将两个数组合并成一个新的数组
  • 将合并后的数组排序
  • 根据数组是奇数,还是偶数进行查找
    • 奇数的话,我们直接取中间值即可
    • 如果是偶数,取中间值和它的后一位,相加后除2,得到的就是中位数

代码:(JAVA实现)

public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int[] ints = new int[nums1.length + nums2.length];
        int index = 0;
        for (int i : nums1) {
            ints[index++] = i;
        }
        for (int i : nums2) {
            ints[index++] = i;
        }
        Arrays.sort(ints);
        int mid = (ints.length-1);
        if (ints.length % 2 != 0) {
            return ints[mid];
        }else {
            double s = (ints[mid] + ints[mid+1]);
            double d = s/2;
            return d;
            }
        }

复杂度分析:

  • 时间复杂度:O(n + m + nlogn)
  • 空间复杂度:O(m+n)

提交结果:

image.png

解题思路:(循环查找)

其实我们并不需要将两个数组真的合并到一起,只需要找到中位数在哪里就可以了

开始的思路是写一个循环,在里面判断是否找到了中位数的位置,找到了就返回结果

len 表示数组合并后的长度

  • 如果是奇数,我们只需要知道(len+1)/2这个数就可以了,遍历的话需要遍历 (len/2) + 1
  • 如果是偶数,我们需要知道第 len/2len/2+1这两个数,也是需要遍历len/2+1次。所以遍历的话,奇数和偶数都是len/2+1次。

返回中位数时,我们用left来存上一次循环后的结果,right存当前循环的结果,在每次循环前把right赋值到left上,也就是上一次循环的结果

  • 当是奇数时,我们只需要返回right即可
  • 当是偶数时,right要加上left,因为偶数需要上一次和最后一次的结果

数组的移动

  • 我们用 AstartBstart分别来表示当前指向num1num2的位置
  • 如果Astart还没有到最后且此时A位置的数组小于B位置的数字,那么就可以向后移动了,即 Astart < m && nums1[Astart] < nusm2[Bstart]
  • 但如果此时num2里已经没有元素了,说明Bstart移动到头了,再移动就会发生越界,所以需要这里需要判断下Bstart是否大于数组长度,这样就不会导致错误了
  • aStart < m && (bStart) >= n || nums1[aStart] < num2[bStart]) 

代码:(JAVA实现)

public static double find(int[] nums1,int[] nums2) {
    int m = nums1.length;
    int n = nums2.length;
    int len = m + n;
    int left = 0;
    int right = 0;
    int Astart = 0, Bstart = 0;
    for (int i = 0; i <= len / 2; i++) {
        left = right;
        if (Astart < m && (Bstart >= n || nums1[Astart] < nums2[Bstart])) {
            right = nums1[Astart++];
        } else {
            right = nums2[Bstart++];
        }
    }

    if (len % 2 == 0) {
        return (left + right) / 2.0;
    } else {
        return right;
    }
}

复杂度分析

  • 时间复杂度:O(m+n)
  • 空间复杂度:O(1)

提交结果

image.png