记录个人算法学习4:寻找两个正序数组的中位数

问题描述

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

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

示例 1:

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

示例 2:

ini 复制代码
输入: nums1 = [1,2], nums2 = [3,4]
输出: 2.50000
解释: 合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

⚠️ 注意闭坑

这道题其实是有歧义的一道题,请你找出并返回这两个正序数组的 中位数 ,较真的同学会以为是分别返回这两个数据的中位数,但实际上人家出题肯定不会那么简单,咱们要降为打击的理解下那些考虑不全的"专家",不要较真。

解题思路

  1. O(log (m+n))就应该想到二分法
  2. 两个数组就应该想到双指针
  3. 我们的目的是找到一个分割点(指针),使得 nums1 左侧的元素和 nums2 左侧的元素加起来正好是合并数组的一半
  4. 提取出隐形条件数组1的索引(指针) 加 数组1的索引(指针) 等于 (m+n)/2 这其实是有代数的思想
  5. 可以定义一个变量i作为数组1的索引(指针),每次遍历中用二分法去重新分配i的值

写代码思路

  1. 找出两个数组中,相对短的那一个,这样遍历时效率高一点
  2. 定义一个变量halfLen 用于存储中位数的索引(也等于数组1的索引和数组2的索引的和)
  3. 第一步先暂定中位数的区间在数组1的最小值和最大值之间
js 复制代码
nums1: [1, 3, 5, 7] nums2: [2, 4, 6, 8, 10]
       └──────────┘
  1. 用二分法去判断数组1中间的值偏大还是偏小
js 复制代码
nums1: [1, 3, 5, 7] nums2: [2, 4, 6, 8, 10]
       └──────────┘        └──────────────┘
           └──┘                   └──┘
              ^                      ^

用二分法得到数组1的索引是2,区间的值是[3,5],右侧对应的索引是3,区间是[6,8] 很明显左侧最大值仍然小于右侧的最小值,那么就说明二分法第一次的索引值偏小了,那么中位数就在当前索引值到最后的那个区间内,再次使用二分法数组1的索引设为3(当前索引加最右侧索引再除以2)左侧区间值是[5,7],右侧的区间值是[4,6],

js 复制代码
nums1: [1, 3, 5, 7] nums2: [2, 4, 6, 8, 10]
              └──┘             └──┘
                 ^                ^

这时候刚好数组1左侧最小值小于于数组2右侧的最大值,而且左侧的最大值大于数组2的最小值,说明刚刚好,因为总数组数量是奇数,所以中位数是两个子数组中较大的左端元素

  1. 考虑下特殊情况

代码实现

js 复制代码
    // 确保nums1是较短的数组(对短的数组遍历效率高)
    if (nums1.length > nums2.length) {
        [nums1, nums2] = [nums2, nums1];
    }

    const m = nums1.length;
    const n = nums2.length;
    let imin = 0;
    let imax = m;
    const halfLen = Math.floor((m + n + 1) / 2);
    //用二分法一步步确定中位数所在的区间
    while (imin <= imax) {
        const i = Math.floor((imin + imax) / 2);
        const j = halfLen - i;

        if (i < imax && nums2[j - 1] > nums1[i]) {
            imin = i + 1; // i偏小了,需要增加
        } else if (i > imin && nums1[i - 1] > nums2[j]) {
            imax = i - 1; // i偏大了,需要减小
        } else { // 达到了正确的划分
            let maxLeft = 0;
            if (i === 0) { maxLeft = nums2[j - 1]; }
            else if (j === 0) { maxLeft = nums1[i - 1]; }
            else { maxLeft = Math.max(nums1[i - 1], nums2[j - 1]); }
            if ((m + n) % 2 === 1) { // 如果总长度是奇数,中位数是两个子数组中较大的左端元素
                return maxLeft;
            }

            let minRight = 0;
            if (i === m) { minRight = nums2[j]; }
            else if (j === n) { minRight = nums1[i]; }
            else { minRight = Math.min(nums1[i], nums2[j]); }

            // 如果总长度是偶数,中位数是两个子数组中较大的左端元素和较小的右端元素的平均值
            return (maxLeft + minRight) / 2.0;
        }
    }
相关推荐
CoovallyAIHub17 小时前
医药、零件、饮料瓶盖……SuperSimpleNet让质检“即插即用”
深度学习·算法·计算机视觉
dragoooon3418 小时前
[优选算法专题二滑动窗口——串联所有单词的子串]
数据结构·c++·学习·算法·leetcode·学习方法
刃神太酷啦18 小时前
C++ 异常处理机制:从基础到实践的全面解析----《Hello C++ Wrold!》(20)--(C/C++)
java·c语言·开发语言·c++·qt·算法·leetcode
Brookty18 小时前
【算法】双指针(二)复写零
学习·算法
胖达不服输18 小时前
「日拱一码」081 机器学习——梯度增强特征选择GBFS
人工智能·python·算法·机器学习·梯度增强特征选择·gbfs
初级炼丹师(爱说实话版)19 小时前
2025算法八股——深度学习——优化器小结
人工智能·深度学习·算法
努力的小帅19 小时前
C++_哈希
开发语言·c++·学习·算法·哈希算法·散列表
Christo319 小时前
TFS-2023《Fuzzy Clustering With Knowledge Extraction and Granulation》
人工智能·算法·机器学习·支持向量机
过河卒_zh156676619 小时前
AI内容标识新规实施后,大厂AI用户协议有何变化?(二)百度系
人工智能·算法·aigc·算法备案·生成合成类算法备案
薰衣草233320 小时前
滑动窗口(2)——不定长
python·算法·leetcode