前端算法(4)

123 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

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

算法的时间复杂度应该为 O(log (m+n)) 。

输入: nums1 = [1,3], nums2 = [2]
输出: 2.00000
解释: 合并数组 = [1,2,3] ,中位数 2

题目思路

思路一

k小数求解,那么前边必然有两个k/2个数,此题中我们在两个数组中分别取前k/2个数,比较上下两个数组第k/2个数,排除掉较小的数所在两者中较小的那k/2个数,那么下次我们就是要求第k-k/2小数,仍然与开头的逻辑类似,我们每次都会删除不符合条件的元素,直到最后要去第1个小数,那么我们比较两个数组的第一个值即可,这里我们考虑一个特殊情况,如果k/2超过数组的长度,那么我们就比较第一个length - 1和第二个k/2这两个数,如果length - 1所指的数大于k/2,那么我们下一轮寻找k-k/2小数,否则下一轮寻找k-(length - 1)小数,这里我们可以做一个特殊处理,将num1永远指向最小的一个,这样当num1length为0的时候,我们直接返回num2[k-1]即可

var findMedianSortedArrays = function(num1, num2) {
  const m = num1.length
  const n = num2.length
  const totalLength = m + n
  // 第k小数,奇数使用
  const k1 = (totalLength + 1) >> 1
  // 第k+1小数,偶数使用
  const k2 = (totalLength + 2) >> 1
  return (getKth(num1, num2, k1) + getKth(num1, num2, k2)) / 2
}
function getKth (num1, num2, k) {
  if (num1.length > num2.length) {
    [num1, num2] = [num2, num1]
  }
  const m = num1.length
  const n = num2.length
  if (num1.length === 0) return num2[k-1]
  if (k === 1) return Math.min(num1[0] || 0, num2[0] || 0)
  let halfK = k >> 1
  let i = Math.min(halfK - 1, m - 1)
  let j = Math.min(halfK - 1, n - 1)
  if (num1[i] < num2[j]) {
    return getKth(num1.slice(i + 1), num2, k - (i + 1))
  } else {
    return getKth(num1, num2.slice(j + 1), k - (j + 1))
  }
}

思路二

我们先进行合并数组并排序,然后再取长度的一半,如一半值带小数点,说明长度为奇数,取一半值向下取整的下标值就为中间值,如果长度值不带小数点,说明长度为偶数,取数组的长度值下标值加数组的长度值下标减一值除2,便是中间值

var findMedianSortedArrays = function(nums1, nums2) {
 function compare(value1, value2) {
    if (value1 < value2) {
      return -1;
    } else if (value1 > value2) {
      return 1;
    } else {
      return 0;
    }
  }
    var all = [...nums1, ...nums2].sort(compare);
    var allLength = all.length;
    var midIndex = allLength / 2;
    if(String(midIndex).includes(".")) {
        return all[Math.floor(midIndex)]
    } else {
        return (all[midIndex] + all[midIndex - 1]) / 2
    }
};