LeetCode 4 Median of Two Sorted Arrays(Tag:Array Difficulty:Hard)

·  阅读 327

前言

关于 LeetCode 数组类型题目的相关解法,可见LeetCode 数组类型题目做前必看,分类别解法总结了题目,可以用来单项提高。觉得有帮助的话,记得多多点赞关注哦,感谢!

题目描述

给定两个大小分别为 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

链接:leetcode-cn.com/problems/me…

题解

  1. 暴力解法,将两个有序数组组合在一起,根据组合后数组的长度来计算其中位数,时间复杂度为 O(n)
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function (nums1, nums2) {
  let nums = []
  let i = 0
  let j = 0
  let k = 0
  while (i < nums1.length && j < nums2.length) {
      if (nums1[i] < nums2[j]) {
          nums[k++] = nums1[i++]
      } else {
          nums[k++] = nums2[j++]
      }
  }
  // nums1数组还有剩余元素
  if (i < nums1.length) {
      nums.push(...nums1.slice(i))
  }
  // nusm2数组还有剩余元素
  if (j < nums2.length) {
      nums.push(...nums2.slice(j))
  }
  let res
  let len = nums.length
  if (len % 2) {
      res = nums[Math.floor(len / 2)]
  } else {
      res = (nums[len / 2] + nums[(len / 2) - 1]) * 0.5
  }
  return res 
复制代码

2、利用有序数组的特性来进行中位数查找,在LeetCode 数组类型题目做前必看一文中,有提到,如果题目中说到有序数组,那么应该首先想到二分搜索,这道题确实可以用二分搜索来解决,关键在于如何将其转换为二分搜索的问题。
假设我们从 nums1 数组中取前 m1 个数,从 nums2 数组中取前 m2 个数,这 m1 个数和 m2 个数共同组成了两个数组合并后的一半的数 k
当 nums1 + nums2 的长度为偶数时,合并后的中位数为 nums1[m1-1] 和 nums[m2-1] 中的较大值 与 nums1[m1] 和 nums2[m2] 中的较小值的平均,对应着合并后 k-1 和 k 位置上的数;
当 nums1 + nums2 的长度为奇数时,合并后的中位数为 nums1[m1 - 1] 和 nums2[m2 -1] 中较大的数,对应着合并后 k-1 位置上的数。
具体可以对照着下图分析:

lc4.png (备注:图来自 花花酱leetcode)

有了这个想法之后,怎么找到对应的 m1, m2 呢?
首先需要确定的一点是,m1 和 m2 只需要知道一个就可以得到另一个,因为 m1 和 m2 的个数为合并后数组的一半,而我们要找的就是在 nums1 中找到满足 nums1[m1] >= nums2[m2-1] 条件的 m1,找到 m1 之后,便可以通过判断奇偶数以及边界条件来得到合并后的中位数了。通过二分搜索加持后,此算法的时间复杂度为 O(logn)

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function (nums1, nums2) {
  const n1 = nums1.length;
  const n2 = nums2.length;
  if (n1 > n2) {
    return findMedianSortedArrays(nums2, nums1);
  }

  const k = Math.floor((n1 + n2 + 1) / 2); // 合并后数组一半的数
  let l = 0;
  let r = n1;
  while (l < r) {
    const m1 = Math.floor((r - l) / 2) + l;
    const m2 = k - m1;
    if (nums1[m1] >= nums2[m2 - 1]) {
      r = m1;
    } else {
      l = m1 + 1;
    }
  }

  const m1 = l;
  const m2 = k - l;

  // k-1 位置上的取值
  const c1 = Math.max(
    m1 <= 0 ? -Number.MAX_VALUE : nums1[m1 - 1], 
    m2 <= 0 ? -Number.MAX_VALUE : nums2[m2 - 1]
  );

  // 合并后的数组为奇数
  if ((n1 + n2) % 2 === 1) {
    return c1;
  }

  // k 位置上的取值
  const c2 = Math.min(
    m1 >= n1 ? Number.MAX_VALUE : nums1[m1],
    m2 >= n2 ? Number.MAX_VALUE : nums2[m2]
  );

  // 合并后的数组为偶数
  return (c1 + c2) / 2;
};
复制代码
分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改