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

LeeCode4.寻找两个正序数组的中位数。小白都能懂。

叠甲,作者是算法白痴,举出的困惑点在大神看来显得很蠢。

一、题目核心(人话版)

给定两个从小到大排好序的数组,找它们合并后的中位数,要求时间复杂度
O(log(m+n))
(必须用二分,暴力合并数组会超时)。
总数奇数:中位数 = 中间那个数
总数偶数:中位数 = 中间两个数的平均值

二、我所有的核心困惑

  • 分割数组后,左边的最大值不一定是 nums1 的分割点 a [i],会不会出错?
  • 为什么只判断 a[i] <= b[j+1] 这一个条件,就能保证左边所有数 ≤ 右边所有数?

解疑惑

对于第一种。不会出现。后续有

intmaxLeft=Math.max(a[i],b[j]);intminRight=Math.min(a[i+1],b[j+1]);

保证划分后的每组的值取正确。

对于第二个困惑。

对于 nums1和 nums2 把 nums1 的前 i 个元素给划分好的第一组。由于nums 本身就是有序的,所以能保证i 的值小于元 nums1 分给第二组的值。这时候,只要再小于 nums2划分给第二组的那些元素的最小值,就能保证 左边所有的数小于等于右边所有的数了

三、终极核心思想(一句话吃透)

我们不需要合并两个数组!把两个数组整体切一刀,平分成左右两堆,只要满足:
左边所有数字 ≤ 右边所有数字左边最大的数 + 右边最小的数 → 直接算出中位数!

四、我的顿悟时刻(解决所有困惑)

顿悟 1:数组有序 = 万能 buff(最关键!)

两个数组天生从小到大排序,这是所有逻辑的根基:
nums1 分割后:前 i 个数的最大值 = a [i],后面所有数 ≥ a [i+1]
nums2 分割后:前 j 个数的最大值 = b [j],后面所有数 ≥ b [j+1]
✅ 结论:我们只需要管 4 个边界值,剩下的数,有序规则帮我们全搞定!

顿悟 2:为什么只判断 a[i] <= b[j+1] 就够了?

a[i]:nums1 左边最大的数
b[j+1]:nums2 右边最小的数
只要「左边最大的数 ≤ 右边最小的数」,左边全体数字必然 ≤ 右边全体数字!不用判断任何其他数,这一个条件直接锁死分割正确性!

顿悟 3:左边最大值不是 a [i]?完全没问题!

分割后左边最大值可能是 a [i],也可能是 b [j],我们根本不在乎!最后一行代码 Math.max(a[i], b[j]) 会自动帮我们取左边最大值,完美兜底!

顿悟 4:二分短数组 = 偷懒防错

二分只操作更短的数组,长数组的分割点 j自动计算,既简化逻辑,又避免数组越界!公式:j = (总长度 + 1) / 2 - i(强制左右两堆数量相等 / 左边多 1 个)

五、保姆级代码步骤(逐行翻译)

  • 步骤 1:保证 nums1 是短数组
    • 二分只二分短数组,降低复杂度,避免越界。
  • 步骤 2:加哨兵(负无穷 / 正无穷)
    • 给数组前后加边界值,彻底解决分割到头部 / 尾部的越界问题,不用写任何边界判断。
  • 步骤 3:二分找最优分割点 i
    核心判断:a[i] <= b[j+1],满足就记录分割点,继续向右找更优解。
  • 步骤 4:计算中位数
    左边最大值:max(a[i], b[j])
    右边最小值:min(a[i+1], b[j+1])
    奇数返回左边最大值,偶数返回平均值。
    六、完整正确代码(标注唯一易错点)
运行classSolution{publicdoublefindMedianSortedArrays(int[]nums1,int[]nums2){// 步骤1:永远把短数组放前面,二分只二分短数组if(nums1.length>nums2.length){int[]tmp=nums1;nums1=nums2;nums2=tmp;}intm=nums1.length;intn=nums2.length;// 步骤2:加哨兵(负无穷/正无穷),防止分割越界int[]a=newint[m+2];int[]b=newint[n+2];a[0]=b[0]=Integer.MIN_VALUE;a[m+1]=b[n+1]=Integer.MAX_VALUE;System.arraycopy(nums1,0,a,1,m);System.arraycopy(nums2,0,b,1,n);// 步骤3:二分查找最优分割点iintleft=0,right=m;intbestI=0;while(left<=right){inti=(left+right)>>>1;// 防溢出写法intj=(m+n+1)/2-i;// 自动计算j// 核心判断:锁死左≤右if(a[i]<=b[j+1]){bestI=i;left=i+1;}else{right=i-1;}}// 步骤4:计算中位数inti=bestI;intj=(m+n+1)/2-i;// ✅ 唯一易错点:b[j] 千万别写成 b[i]!intmaxLeft=Math.max(a[i],b[j]);intminRight=Math.min(a[i+1],b[j+1]);// 奇数/偶数判断return(m+n)%2>0?maxLeft:(maxLeft+minRight)/2.0;}}

七、终极总结(新手必背)
有序数组是爹:所有判断都依赖数组天生有序,只看 4 个边界值就够了;
核心判断:a[i] <= b[j+1] → 左边全体 ≤ 右边全体;
不用纠结左边最大值是谁:max(a[i],b[j]) 自动兜底;
二分短数组:简单、高效、不越界;
哨兵机制:解决所有边界问题,代码更简洁。
这道 Hard 题,吃透「分割思想 + 数组有序」这两个点,直接降维打击!希望我的总结能帮到和我一样的算法小白~

http://www.jsqmd.com/news/478671/

相关文章:

  • JAVA基础二
  • ContentProvider与Uri权限:跨应用数据共享
  • 攻防世界 misc题心仪的公司
  • Linux:进程调度
  • 软件测试定义、目的、调试、需求概念、软件生命周期与测试流程
  • 学习率调度的艺术:从Warmup到余弦退火,掌握深度学习的训练节奏
  • AI 辅助编程阶段化开发 SOP
  • 大数据安全必修课:数据隐私保护的7大核心原则
  • 56767786
  • 工业缺陷检测的新范式:2025-2026年零样本检测技术全景扫描
  • 51单片机的【智能火灾报警系统】仿真设计
  • 北京营养自愈力专家亲测分享:这样找最靠谱!
  • 代码上传到gitee
  • 我不知道起什么我就是找个地方说话
  • 量化开发实战手册·第1篇:数据源选型指南——如何为你的策略找到最合适的行情接口?
  • Flutter 三方库 flutter_localized_locales 鸿蒙适配指南 - 实现工业级全球化多语言映射与区域感知实战
  • pikachu靶场——SQL-Inject—2(Kali系统)占位符
  • C++ 标准库提供了一组丰富的输入/输出功能
  • 腾讯六宫格验证码破解
  • 太猛了!用 OpenClaw-RL,AI 边聊天边自我进化,「白嫖」用户交互数据训出更强模型?
  • Flutter 三方库 angel3_cors 鸿蒙适配指南 - 实现高性能全栈跨域安全治理与通讯防护实战
  • 了解动态内存在 C++ 中是如何工作的是成为一名合格的 C++ 程序员必不可少的
  • OpenClaw 彻底卸载指南:从反复踩坑到一键完美清理】
  • 江苏哪里有三防布厂家?跑断腿摸出的实体大厂
  • 编译性语言不如解释性语言跨平台性好
  • Linux 网络命令速查:告别 `ifconfig`,拥抱 `ip`
  • 告别“纸上谈兵”!场景AI助力企业数智化落地
  • 解释性语言每执行一次就要翻译一次,效率比较低
  • Flutter 三方库 shelf_router_discovery 鸿蒙适配指南 - 实现服务端路由自动注册、在 OpenHarmony 上打造极致解耦的云端治理实战
  • 联合循环——23 电厂建筑屋顶防雷,盘柜中性点地排设计说明