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

76 阅读2分钟

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

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

解题方法一:二分查找法

/**********JavaScript**************/
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    // 二分查找 先找到较短元素分割线的位置
    // 防止
    // 1、较短的数组,在分割线左边没有元素
    // 2、较短的数组,在分割线右边没有元素
    if(nums1.length > nums2.length) {
        let arr = nums1;
        nums1 = nums2;
        nums2 = arr
    }
     var m = nums1.length,
        n = nums2.length;
    //  分割线左边的元素的数量合计,需要满足
    var totalLeft = Math.floor((m + n + 1)/2);

    var left = 0, // 左指针
        right = m; // 右指针
    while(left < right){
        // 取中间位置,由于是向下取整,为了防止i=0 因此right - left + 1
        // i 是nums1分割线左边元素的个数(也是nums1分割线的位置), 
        // j是nums2分割线左边元素的个数(也是nums2分割线的位置), 
        var i = left + Math.floor((right - left + 1) / 2);
        var j = totalLeft - i;
        // 需要找到满足 
        //1、 nums1分割线左侧元素的值 <= nums2分割线右侧元素的值,即 nums1[i-1] <= nums2[j]
        //2、 nums2分割线左侧元素的值 <= nums1分割线右侧元素的值,即 nums1[j-1] <= nums2[i]
        if ( nums1[i-1] > nums2[j]) {
            // 当 nums1分割线左侧元素的值 > nums2分割线右侧元素的值,
            // 说明分割线太靠右边,因此右指针往左挪, [left, i-1]
            right = i - 1;
        } else {
            // 否则左指针往右挪, [i, right]
            left = i;
        }
    }
    var i = left, // nums1分割线
        j = totalLeft - left; // nums2分割线
    // nums1分割线左侧元素的值; 如果nums1分割线左侧没有元素(i = 0),给nums1LeftMax设置无穷小
    var nums1LeftMax = i === 0 ? -Infinity : nums1[i - 1];
    // nums1分割线右侧元素的值; 如果nums1分割线右侧没有元素(i = m),给nums1RightMax设置无穷大
    var nums1RightMin = i === m ? Infinity :  nums1[i];
    // nums2分割线左侧元素的值; 如果nums2分割线左侧没有元素(j = 0),给nums2LeftMax设置无穷小
    var nums2LeftMax = j === 0 ? -Infinity : nums2[j - 1];
    //  nums2分割线右侧元素的值; 如果nums2分割线右侧没有元素(j = m),给nums1RightMax设置无穷大
    var nums2RightMin = j === n ? Infinity :  nums2[j];
    // 奇数 取nums1、num2分割线左侧最大值即可
    if ((m + n) % 2 == 1) {
        return Math.max(nums1LeftMax, nums2LeftMax);
    } else{
        // 偶数 (nums1、num2分割线左侧最大值 + nums1、num2分割线右侧最小值) / 2
         return (Math.max(nums1LeftMax, nums2LeftMax) + Math.min(nums1RightMin, nums2RightMin)) / 2;
    }
};