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

110 阅读3分钟

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

中位数:回顾一下九年义务教育知识点,就是一个数组中间的数。

偶数个:中位数就是中间两个数的平均数。

奇数个:中间的那个数。

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

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

提示:

  • nums1.length == m
  • nums2.length == n
  • 0 <= m <= 1000
  • 0 <= n <= 1000
  • 1 <= m + n <= 2000
  • -10^6 <= nums1[i], nums2[i] <= 10^6
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    let len1 = nums1.length, len2 = nums2.length
    if (len1 > len2) return findMedianSortedArrays(nums2, nums1)//对nums1和nums2中长度较小的二分
    let len = len1 + len2//总长
    let start = 0, end = len1 //进行二分的开始和结束位置
    let partLen1, partLen2
​
    while (start <= end) {
        partLen1 = (start + end) >> 1//nums1二分的位置
        partLen2 = ((len + 1) >> 1) - partLen1//nums2二分的位置
​
        //L1:nums1二分之后左边的位置,L2,nums1二分之后右边的位置
        //R1:nums2二分之后左边的位置,R2,nums2二分之后右边的位置
​
        //如果左边没字符了,就定义成-Infinity,让所有数都大于它,否则就是nums1二分的位置左边一个
        let L1 = partLen1 === 0 ? -Infinity : nums1[partLen1 - 1]
        //如果左边没字符了,就定义成-Infinity,让所有数都大于它,否则就是nums2二分的位置左边一个
        let L2 = partLen2 === 0 ? -Infinity : nums2[partLen2 - 1]
        //如果右边没字符了,就定义成Infinity,让所有数都小于它,否则就是nums1二分的位置
        let R1 = partLen1 === len1 ? Infinity : nums1[partLen1]
        //如果右边没字符了,就定义成Infinity,让所有数都小于它,否则就是nums1二分的位置
        let R2 = partLen2 === len2 ? Infinity : nums2[partLen2]
​
        if (L1 > R2) {//不符合交叉小于等于 继续二分
            end = partLen1 - 1
        } else if (L2 > R1) {//不符合交叉小于等于 继续二分
            start = partLen1 + 1
        } else { // L1 <= R2 && L2 <= R1 符合交叉小于等于
            return len % 2 === 0 ?
                (Math.max(L1, L2) + Math.min(R1, R2)) / 2 : //长度为偶数返回作左侧较大者和右边较小者和的一半
                Math.max(L1, L2)  //长度为奇数返回作左侧较大者
        }
    }
};

分析:这道题,如果我们使用传统的方式计算,我们就是将数组合并,排序,最后找到中间的数。但是我们看要求是:时间复杂度有要求,我们一看是O(log^{(m+n)}),我们其实就是可以确定我们使用二分法来实现。

我们常规算法:

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    // 合并数组
    const arr =[...nums1,...nums2]
    // 如果数组只有一位 直接返回该数字
    if(arr.length<=1)return arr[0]
    // 把数组按照正序排序
    arr.sort(function(a,b){return a - b})
    // 数组长度
    const len = arr.length
    // 判断数组长度奇还是偶
    // 奇数返回
    if(len%2!==0) return arr[(len-1)/2]
    // 偶数处理 截取中间的俩个数字
    const oArr = arr.slice(len/2-1,len/2+1)
    return (oArr[0]+oArr[1])/2
};