JS算法之寻找两个正序数组的中位数

581 阅读1分钟

这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战

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

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

难度:困难

题目:leetcode-cn.com/problems/me…

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

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

示例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
  • -10^6 <= nums1[i], nums2[i] <= 10^6

题解

法一 暴力法

这个方法不符合题目要求,但是leetcode可A。

合并两个排序数组,使用两个指针分别指向两个数组,通过比较大小的方式,将值存入新数组,若有一个数组循环结束,则将另一个数组剩下的所有值存入新数组。

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
  const mergeArr = [];
  let i = 0, j = 0;
  while(i < nums1.length && j < nums2.length){
    if(nums1[i] > nums2[j]) {
      mergeArr.push(nums2[j++])
    }else{
      mergeArr.push(nums1[i++])
    }
  }
  while(i < nums1.length) {
    mergeArr.push(nums1[i++]);
  }
  while(j < nums2.length) {
    mergeArr.push(nums2[j++]);
  }
  
  const len = mergeArr.length;
  return len % 2 === 1 ? mergeArr[Math.floor(len / 2)] : (mergeArr[len / 2] + mergeArr[len / 2 - 1]) / 2;
}

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

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

法二 二分查找

由题目得知,两个数组都是正序的,很容易就可以想出使用二分查找的方法。

本质就是直接查找出对两个数组(A、B)进行不断有条件的划分,直到满足条件:

  • leftA的长度 + leftB的长度 = (两个数组长度之和 + 1)/ 2
  • A左边最大(maxLeftA),A右边最小(minRightA),B左边最大(maxLeftB),B右边最小(minRightB)满足:(maxLeftA <= minRightB && maxLeftB <= minRightA)

median就在这四个数中,再根据奇数或者偶数对数据进行处理即可。

/**
 * 二分解法
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */var findMedianSortedArrays = function(nums1, nums2) {
  if(nums1.length > nums2.length) {
    [nums1, nums2] = [nums2, nums1];
  }
  const m = nums1.length, n = nums2.length;
  let low = 0, high = m;
  while(low <= high) {
    const i = low + Math.floor((high - low) / 2);
    const j = Math.floor((m + n + 1) / 2) - i;
    
    const maxLeftNums1 = i === 0 ? -Infinity : nums1[i - 1];
    const minRightNums1 = i === m ? Infinity : nums1[i];
    
    const maxLeftNums2 = j === 0 ? -Infinity : nums2[j - 1];
    const minRightNums2 = j === n ? Infinity : nums2[j];
    
    if(maxLeftNums1 <= minRightNums2 && minRightNums1 >= maxLeftNums2) {
      return (m + n) % 2 === 1 
        ? Math.max(maxLeftNums1, maxLeftNums2)
        : (Math.max(maxLeftNums1, maxLeftNums2) + Math.min(minRightNums1,minRightNums2)) / 2
    } else if(maxLeftNums1 > minRightNums2) {
      high = i - 1;
    } else {
      low = low + 1;
    }
  }
}

时间复杂度:O(log(min(m,n)))

空间复杂度:O(log(min(m,n)))


坚持每日一练!前端小萌新一枚,希望能点个+在看哇~