算法题:寻找两个正序数组的中位数

101 阅读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

中位数的定义

中位数是指一个数据集的中间值,对于偶数个数的数组,中位数是中间两个数的平均值;对于奇数个数的数组,中位数是中间处的数。

假设我们有两个有序数组 nums1nums2

  • mnums1 的长度,nnums2 的长度。
  • 我们需要找到两个数组的中位数,会将这两个数组合并成一个数组,如果总长度是奇数则取中间值,如果是偶数则取中间两个值的平均。

思路

我们在想要查找的中位数位置上,定义分割线在两个数组的某个位置:

  • nums1 中的分割位置为 i,因此在 nums2 中的分割位置为 (m + n + 1) / 2 - i
  • 这保证了左边所有的元素都是小于等于右边所有的元素。

然后我们检查以下条件:

  1. nums1[i-1] <= nums2[j] (左侧 nums1 的最大值小于等于右侧 nums2 的最小值)
  2. nums2[j-1] <= nums1[i] (左侧 nums2 的最大值小于等于右侧 nums1 的最小值)

当满足以上条件时,我们可以找到中位数:

  • 如果 (m + n) 为偶数,中位数是 (max(nums1[i-1], nums2[j-1]) + min(nums1[i], nums2[j])) / 2
  • 如果 (m + n) 为奇数,中位数是 max(nums1[i-1], nums2[j-1])

JavaScript代码实现

以下是这个算法的 JavaScript 实现:

function findMedianSortedArrays(nums1, nums2) {
    let m = nums1.length, n = nums2.length;

    // 确保 nums1 是短的那个数组
    if (m > n) {
        [nums1, nums2, m, n] = [nums2, nums1, n, m];
    }

    let left = 0, right = m, halfLen = Math.floor((m + n + 1) / 2);

    while (left <= right) {
        let i = Math.floor((left + right) / 2); // nums1 的分割位置
        let j = halfLen - i; // nums2 的分割位置

        let maxLeft1 = (i === 0) ? -Infinity : nums1[i - 1];
        let minRight1 = (i === m) ? Infinity : nums1[i];

        let maxLeft2 = (j === 0) ? -Infinity : nums2[j - 1];
        let minRight2 = (j === n) ? Infinity : nums2[j];

        if (maxLeft1 <= minRight2 && maxLeft2 <= minRight1) {
            // 找到了合适的分割
            if ((m + n) % 2 === 0) {
                return (Math.max(maxLeft1, maxLeft2) + Math.min(minRight1, minRight2)) / 2;
            } else {
                return Math.max(maxLeft1, maxLeft2);
            }
        } else if (maxLeft1 > minRight2) {
            right = i - 1; // 移动分割线向左
        } else {
            left = i + 1; // 移动分割线向右
        }
    }

    throw new Error("Input arrays are not sorted.");
}

// Example usage:
const nums1 = [1, 3];
const nums2 = [2];
console.log(findMedianSortedArrays(nums1, nums2)); // Output: 2.0

代码解析

  1. 首先,我们确保 nums1 是较短的那一个数组,以便减少遍历空间。
  2. 然后,我们使用二分查找来找到合适的分割位置 i,并计算对应的 j
  3. 对于每个分割,我们检查左右两部分的条件是否满足,如果满足就可以计算中位数。
  4. 如果不满足,我们根据条件决定移动哪一侧的搜索范围。
  5. 最后返回计算的中位数。

通过这种方法,我们能在对数时间内找到中位数。