当前位置: 首页 > article >正文

一起学习LeetCode热题100道(68/100)

68.寻找两个正序数组的中位数(学习)

给定两个大小分别为 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
-106 <= nums1[i], nums2[i] <= 106

解析:
一、初始化:
1.首先,我们假设nums1是较短的数组(如果不是,则交换nums1和nums2),这样可以减少搜索空间,提高算法效率。
2.m和n分别是nums1和nums2的长度。
3.halfLen是目标中位数在合并后数组中的位置(对于奇数长度,是中间那个数的位置;对于偶数长度,是中间两个数左边的那个数的位置加1,这样便于计算)。

二、二分查找:
1.在nums1上使用一个二分查找框架,左指针left初始化为0,右指针right初始化为m(注意这里是对nums1的长度进行二分,而不是整个合并数组的长度)。
2.在每次迭代中,计算中间位置i = (left + right) / 2,并据此计算出nums2中对应的j = halfLen - i。

三、调整分割点:
1.检查i和j是否合法(即i不为0时nums1[i-1]存在,j不为n时nums2[j-1]存在)。
2.通过比较nums1[i-1]和nums2[j],以及nums1[i]和nums2[j-1](如果存在的话),来确定i是否需要向左或向右移动。
3.如果nums2[j-1] > nums1[i],说明i选小了,应该向右移动(即增大i),所以更新left = i + 1。
4.如果nums1[i-1] > nums2[j],说明i选大了,应该向左移动(即减小i),所以更新right = i - 1。

四、找到中位数:
1.当left == right时,循环结束,此时找到了合适的i和j。
2.根据i和j的值,可以确定左边元素的最大值和右边元素的最小值(可能需要从nums1和nums2中选取)。
3.如果总长度(m+n)是奇数,则中位数就是左边元素的最大值。
4.如果总长度(m+n)是偶数,则中位数是左边元素最大值和右边元素最小值的平均值。

五、处理边界情况:
1.需要注意处理i或j为0或达到数组末尾的情况,确保不会访问不存在的数组元素。

var findMedianSortedArrays = function (nums1, nums2) {
    // 将 nums2 合并到 nums1 中,以保持 nums1 长度较短,优化性能  
    if (nums1.length > nums2.length) {
        [nums1, nums2] = [nums2, nums1];
    }

    let m = nums1.length;
    let n = nums2.length;

    // 初始化左右指针  
    let left = 0, right = m;
    let halfLen = Math.floor((m + n + 1) / 2);

    while (left <= right) {
        let i = Math.floor((left + right) / 2);
        let j = halfLen - i;

        if (i < m && nums2[j - 1] > nums1[i]) {
            // i 太小,需要增加  
            left = i + 1;
        } else if (i > 0 && nums1[i - 1] > nums2[j]) {
            // i 太大,需要减小  
            right = i - 1;
        } else {
            // i 刚好  
            let maxLeft;
            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) {
                // 奇数长度,中位数就是 maxLeft  
                return maxLeft;
            }

            // 偶数长度,需要找到右半部分的最小值  
            let minRight;
            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;
        }
    }

    // 理论上不会执行到这里  
    throw new Error('No valid median found');
};

http://www.kler.cn/a/288806.html

相关文章:

  • Spring-Webflux + Reactor + Netty 初体验
  • 字节跳动Android面试题汇总及参考答案(80+面试题,持续更新)
  • 鸿蒙next版开发:ArkTS组件点击事件详解
  • 【插件】多断言 插件pytest-assume
  • 智能电视/盒子的应用管理——通过ADB工具优化体验
  • 事件循环 -- 资源总结(浏览器进程模型、事件循环机制、练习题)
  • 机器学习如何助力网络生物学
  • 合宙LuatOS开发板Core_Air780EP使用说明
  • APP长文本内容编辑器功能实现方案
  • MySQL之UDF提权复现
  • 老师怎样发布新生月考成绩查询?
  • 车载测试协议:ISO-14229、ISO-15765、ISO-11898、ISO-26262【实操项目学习】
  • jmeter中上传文件接口,当文件名为中文时出现乱码
  • JPG转SVG,分享便捷的转换方法
  • 【EI稳定检索】2024年第三届环境工程与可持续能源国际会议
  • 【SpringBoot】自动配置原理
  • MySQL知识点复习 - 事务篇
  • Linux性能调优,从优化思路说起
  • MariaDB VS MySQL
  • Python数据分析实战,兰州市二手房市场深度分析
  • 【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(二十一)
  • Unity 不规则进度条显示根据点对点进行
  • yolov9目标检测pyside6可视化检测界面python源码-用于计数统计-摄像头可用
  • jquery swiper插件的用法
  • c++vscode多文件实现通讯录管理系统
  • DRY原则-用函数和模块化来避免重复代码