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

186 阅读2分钟

RT,注释都在代码中,直接上代码。

/**
 * 寻找两个正序数组的中位数
 * 题目描述:给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
 * 请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
 * 你可以假设 nums1 和 nums2 不会同时为空。
 *
 * 示例 1:
 * nums1 = [1, 3]
 * nums2 = [2]
 * 则中位数是 2.0
 *
 * 示例 2:
 * nums1 = [1, 2]
 * nums2 = [3, 4]
 * 则中位数是 (2 + 3)/2 = 2.5
 * ------------------------
 * 命题关键字:二分思想、数学问题
 *
 * 将两个数组进行分隔,用 s1 s2 分别表示 num1 nums2 数组分隔后各自分割线左侧的元素的数量
 * s1 s2 的和显然为总长度的一半【题意就相当于把整个数组拼起来然后取中位数,这时中位数左侧元素的个数就是总长度的一半】
 * 在假设已知 s1 s2 应该是什么样的值的时候,如何计算中位数是显而易见的。
 * 两个数组总长度为偶数时,中位数按照定义需要取中间两个元素的平均值, 
 * 结果为::(左侧较大的+右侧较小的值)/2
 *
 * 两个数组总长度为奇数时,中位数按照定义需要取正中间一个元素, s1 s2 的和为总长度的一半向下取整
 * 结果为::右侧较小的值
 *
 *
 * 但难点是,小册上 s1 s2 如何确定边界?即,分割点如何确定?
 *
 * 分割点 s1 s2 的可选方式是是唯一的,下面分为偶数、奇数去讨论
 * 偶数的情况,如: 1 2 3 4 5 6 7 8 9 10
 * s1 + s2 = 5
 * 1 3 5 | 7 9
 *   2 4 | 6 8 10
 * 左侧取5,右侧取6
 *
 * s1 + s2 = 5
 *   1 3 | 5 7 9
 * 2 4 6 | 8 10
 * 这种分隔就不行,左侧的值要统统小于右侧的值
 *
 *
 * 奇数的情况,如: 1 2 3 4 5 6 7
 * s1 + s2 = 3
 *   1 | 3  5 7
 * 2 4 | 6
 * 这种分隔就不行,左侧的值要统统小于右侧的值
 *
 * s1 + s2 = 3
 * 1 3 | 5 7
 *   2 | 4 6
 * 取右侧较小值4
 *
 *
 * s1 + s2 = 3
 * 1 3 5 7
 * 2 4 6 |
 * 这就不行了,右边没东西?
 *
 * !!!!边界的结论:左侧的最大值要小于右侧的最小值;而且分割线不能在边界上
 *
 */
funMap.findMedianSortedArrays = () => {
  // let nums1 = [1, 3, 5, 7, 9]
  // let nums2 = [2, 4, 6, 8, 10]

  let nums1 = [1, 3, 5, 7]
  let nums2 = [2, 4, 6]

  function findMedianSortedArrays(nums1, nums2) {
    let len1 = nums1.length
    let len2 = nums2.length
    // 奇数
    let isOdd = (len1 + len2) % 2 !== 0
    let sLen = Math.floor((len1 + len2) / 2)

    console.log('isOdd', isOdd)

    // 这里约定 i 是用于 nums1 数组,i < len1 是防止分隔到边缘
    // i 就相当于 s1,表示长度,而不是表示下标
    for (let i = 1; i < sLen && i < len1; i++) {
      let j = sLen - i

      let leftMax = Math.max(nums1[i - 1], nums2[j - 1])
      let rightMin = Math.min(nums1[i], nums2[j])

      console.log('leftMax, rightMin', leftMax, rightMin)

      // 边界,跳过去,试下一个分隔方式
      if (leftMax > rightMin) {
        continue
      }

      if (isOdd) {
        return rightMin
      } else {
        return (leftMax + rightMin) / 2
      }
    }
  }

  console.log(findMedianSortedArrays(nums1, nums2))
}

funMap.findMedianSortedArrays()