打怪升级之旅第6天

115 阅读3分钟

寻寻觅觅

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

题目描述

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

进阶:你能设计一个时间复杂度为O(log(m+n)) 的算法解决此问题吗?

示例

输入 nums1 = [1,3], nums2 = [2] 输出: 2.00000

中位数 一般是在统计学 中描述一组数据处于中间的数值 偶数 取中间两位的平均值

合并数组排序

function findMedianSortedArrays(nums1, nums2){
  let n  = nums1.length
  let m =  nums2.length
  let total = m + n
  let arr = nums1.concat(nums2)
  arr.sort((a,b)=>{
    return a - b
  })
  let l = arr[(m+n)/2]
  let r = arr[(m+n)/2 - 1]
  if(total % 2 === 0){
    return (l+ r)/2
  }else{
    return arr[(m+n-1)/2]
  }
}

分治

思路分析

已知两个数组长度m,n total = m + n

  • 奇数 我们就找 第total/ 2个的数就是中位数 total/2 不是下标
  • 偶数 我们就找 第total/ 2个和第total/2 + 1个数的平均值

如何找第k个数 我就每次找两个数组的k/2 进行比较

  • 谁比较小 就证明第k个不会出现在这个数组的 k/2的下标之前 就去掉这个这个数组的 k/2的元素
  • k也需要减去这个 k/2
  • 注意: js没有整形

我认为自己写的有问题 但leetcode 通过了 有没有路过的大佬 看一下

请看code !!!

function find(n1, i,n2,j,k){
  if(n1.length - i > n2.length  - j) return find(n2,j,n1,i,k)
  if(i >= n1.length) return n2[j + k - 1]
  if(k === 1) {
    return Math.min(n1[i],n2[j])
  }
  let halfK = Math.floor(k/2)
  let si = i + halfK
  let sj = j + halfK
  if(n1[si - 1] < n2[sj - 1]){
    return find(n1, si, n2, j, k - halfK)
  }else{
    return find(n1, i, n2, sj, k - halfK)
  }
}

function findMedianSortedArrays1(nums1, nums2){
  let n  = nums1.length
  let m =  nums2.length
  let total = m + n
  let halfTotal = Math.ceil(total/ 2)
  if(total % 2 === 0){
   let left = find(nums1, 0,nums2,0,halfTotal)
   let right = find(nums1, 0,nums2,0,halfTotal + 1)
   return (left + right) / 2
  }else{
    return find(nums1, 0,nums2,0,halfTotal)
  }
}
console.time('result1')
let result1 = findMedianSortedArrays1([1],[2,3,5,6])
console.timeEnd('result1') // 0.133ms
console.log(result1) // 3


这个算法复杂度 为 O(logmin(m+n))


// 思路 用一条边界把两个数组划分为左右两个相等的部分 若总长度为奇数 则让左半部分多一个数
//  通过边界值去求中位数

function findMedianSortedArrays2(nums1, nums2) {
  let m = nums1.length;
  let n = nums2.length;
  if (m > n) {
    return findMedianSortedArrays2(nums2, nums1);
  }
  let iMin = 0;
  let iMax = m;
  while (iMin <= iMax) {
    let i = Math.floor((iMin + iMax) / 2);
    let j = Math.floor((m + n + 1) / 2) - i;
    // i 和 j 满足条件的情况是  j-1 < i  && j > i-1
    if (j !== 0 && i !== m && nums2[j - 1] > nums1[i]) {
    // 左下大于右上 代表 i需要增大 有序 
      iMin = i + 1;
    } else if (i !== 0 && j !== n && nums1[i - 1] > nums2[j]) {
       // 如果左上 大于右下
       iMax = i - 1;
    } else {
      let maxLeft = 0;
      if (i === 0) {
        // i- 1 不存在 左上不存在
        maxLeft = nums2[j - 1];
      } else if (j === 0) {
        // j - 1 不存在 左下不存在
        maxLeft = nums1[i - 1];
      } else {
        maxLeft = Math.max(nums1[i - 1], nums2[j - 1]);
      }
      if(m + n % 2 !== 0) return maxLeft
      let minRight = 0
      if(i === m){
        // 证明右上不存在
        minRight = nums2[j]
      }else if(j === n){
        // 证明右下不存在
        minRight = nums1[i]
      }else {
        minRight = Math.min(nums1[i],nums2[j])
      }

      return (minRight + maxLeft) /2
     }
  }
}


console.time("result2");
let result2 = findMedianSortedArrays2([1], [2, 3, 5, 6]);
console.timeEnd("result2"); // 0.133ms
console.log(result1); // 3

Baybay!!!