LeetCode 4:寻找两个正序数组的中位数

在这里插入图片描述

问题定义与核心挑战

给定两个有序(升序)数组 nums1nums2,要求找到它们的中位数,且算法时间复杂度为 O(log(m+n))mn 分别是两个数组的长度)。

中位数定义

  • 若合并后数组长度为奇数,中位数是中间位置的元素(如 [1,2,3] 的中位数是 2)。
  • 若合并后数组长度为偶数,中位数是中间两个元素的平均值(如 [1,2,3,4] 的中位数是 (2+3)/2=2.5)。

常规方法的不足

若直接合并两个数组(时间复杂度 O(m+n)),虽能解决问题,但无法满足题目对时间复杂度的严格要求(O(log(m+n)))。因此,必须利用数组有序的特性,通过 二分查找 避免完全合并。

核心思路:二分法定位分割点

中位数的本质是将合并后的数组划分为左右两部分,使得:

  • 左边所有元素 ≤ 右边所有元素;
  • 左边元素个数 ≥ 右边(奇数长度时左边多一个)。

对于两个有序数组,我们可以通过二分查找分割点,将 nums1nums2 分别划分为左右两部分,使得:

  • nums1 的左半部分 + nums2 的左半部分 nums1 的右半部分 + nums2 的右半部分;
  • 左半部分总元素数为 (m+n+1)//2(向上取整,保证奇数长度时左边多一个)。

算法步骤详解

步骤 1:统一数组长度(优化二分范围)

为了减少二分查找的范围,确保 nums1 是较短的数组(若 nums1 更长,则交换 nums1nums2)。这样,二分查找仅需在较短数组上进行,降低时间复杂度。

int m = nums1.length, n = nums2.length;
if (m > n) {// 交换数组,确保 nums1 是较短的int[] temp = nums1;nums1 = nums2;nums2 = temp;m = nums1.length;n = nums2.length;
}
步骤 2:二分查找分割点

nums1 中二分查找分割点 i,并计算 nums2 的对应分割点 j

  • i 表示 nums1 左半部分的元素个数(范围:0 ≤ i ≤ m);
  • j = (m + n + 1) // 2 - i,保证左半部分总元素数为 (m+n+1)//2(向上取整)。
int left = 0, right = m;
while (left < right) {// 向上取整,避免死循环(如 left=1, right=2 时,mid=2)int mid = (left + right + 1) / 2; int j = (m + n + 1) / 2 - mid;if (nums1[mid-1] > nums2[j]) {// i 太大,左移右边界right = mid - 1;} else {// i 太小,右移左边界left = mid;}
}
int i = left;
int j = (m + n + 1) / 2 - i;
步骤 3:处理边界值(分割点越界)

分割点 ij 可能为 0(左半部分为空)或等于数组长度(右半部分为空),需用极值(-∞+∞)处理:

// nums1 左半部分的最大值(i=0 时,左半部分为空,设为 -∞)
double nums1_left = (i == 0) ? Integer.MIN_VALUE : nums1[i-1];
// nums1 右半部分的最小值(i=m 时,右半部分为空,设为 +∞)
double nums1_right = (i == m) ? Integer.MAX_VALUE : nums1[i];
// nums2 左半部分的最大值(j=0 时,左半部分为空,设为 -∞)
double nums2_left = (j == 0) ? Integer.MIN_VALUE : nums2[j-1];
// nums2 右半部分的最小值(j=n 时,右半部分为空,设为 +∞)
double nums2_right = (j == n) ? Integer.MAX_VALUE : nums2[j];
步骤 4:计算中位数

根据合并后数组的长度(m+n)的奇偶性,计算中位数:

  • 奇数:左半部分最大值(max(nums1_left, nums2_left));
  • 偶数:左半部分最大值与右半部分最小值的平均值((max(...) + min(...)) / 2)。
if ((m + n) % 2 == 1) {// 奇数长度,中位数是左半部分最大值return Math.max(nums1_left, nums2_left);
} else {// 偶数长度,中位数是左右部分的中间值平均return (Math.max(nums1_left, nums2_left) + Math.min(nums1_right, nums2_right)) / 2.0;
}

完整代码(Java)

class Solution {public double findMedianSortedArrays(int[] nums1, int[] nums2) {int m = nums1.length, n = nums2.length;// 确保 nums1 是较短的数组,优化二分范围if (m > n) {int[] temp = nums1;nums1 = nums2;nums2 = temp;m = nums1.length;n = nums2.length;}int left = 0, right = m;while (left < right) {// 向上取整,避免死循环int mid = (left + right + 1) / 2; int j = (m + n + 1) / 2 - mid;if (nums1[mid - 1] > nums2[j]) {// i 太大,左移右边界right = mid - 1;} else {// i 太小,右移左边界left = mid;}}int i = left;int j = (m + n + 1) / 2 - i;// 处理边界值:左半部分或右半部分为空的情况double nums1_left = (i == 0) ? Integer.MIN_VALUE : nums1[i - 1];double nums1_right = (i == m) ? Integer.MAX_VALUE : nums1[i];double nums2_left = (j == 0) ? Integer.MIN_VALUE : nums2[j - 1];double nums2_right = (j == n) ? Integer.MAX_VALUE : nums2[j];// 计算中位数if ((m + n) % 2 == 1) {return Math.max(nums1_left, nums2_left);} else {return (Math.max(nums1_left, nums2_left) + Math.min(nums1_right, nums2_right)) / 2.0;}}
}

关键逻辑解析

1. 数组交换的意义

将较长数组与较短数组交换,确保二分查找在较短数组上进行,减少二分次数(如 m=3, n=5 时,二分范围是 0~3 而非 0~5)。

2. 分割点的数学意义

j = (m + n + 1) // 2 - i 保证 左半部分总元素数为 (m+n+1)//2

  • m+n 为奇数,左半部分比右半部分多 1 个元素,中位数是左半部分的最大值;
  • m+n 为偶数,左半部分与右半部分元素数相等,中位数是两部分的中间值平均。
3. 边界值处理

通过 Integer.MIN_VALUEInteger.MAX_VALUE 处理“左半部分为空”或“右半部分为空”的情况,确保比较逻辑的一致性。

4. 二分循环的细节

使用 (left + right + 1) / 2 向上取整,避免 leftright 相邻时的死循环(如 left=1, right=2 时,mid=2 而非 1,确保范围缩小)。

该方法通过 二分查找分割点 避免了数组的完全合并,将时间复杂度优化到 O(log(min(m,n)))(等价于 O(log(m+n))),是处理“两个有序数组中位数”问题的经典方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91274.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91274.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/91274.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

独立站如何吃掉平台蛋糕?DTC模式下的成本重构与利润跃升

一、成本结构革命&#xff1a;从「流量税」到「用户终身价值」亚马逊卖家需支付15%佣金12%广告费&#xff0c;导致每$100收入中平台抽成$27。而成熟独立站通过SEO&#xff08;自然流量占比超40%&#xff09;和社交媒体内容引流&#xff0c;将获客成本压缩至$8-$15。更关键的是用…

应用驱动 协同创新:中国人工智能开启高质量发展新篇章

人工智能技术的突破性发展正引发全球产业格局的深刻变革。在2025年这个关键节点&#xff0c;中国以"应用导向"为战略支点&#xff0c;依托新型举国体制优势&#xff0c;正在构建具有中国特色的人工智能发展体系&#xff0c;为全球智能革命贡献东方智慧。一、战略布局…

ZKMall商城开源本地部署指南

1. 开发环境配置 以下是开发工具的最低版本要求。在继续之前&#xff0c;请务必安装所有必需的依赖项。 工具版本JDK17MySQL5.7.3Redis5.0Maven3.9.5NodeJS20.18.0 1.1 安装资源 如需详细的安装指南&#xff0c;您可以参考以下教程&#xff1a; JDK: 菜鸟教程 Java 环境搭建…

《使用Qt Quick从零构建AI螺丝瑕疵检测系统》——8. AI赋能(下):在Qt中部署YOLOv8模型

目录一、概述1.1 背景介绍&#xff1a;从“训练”到“部署”1.2 学习目标二、在C中集成ONNX模型2.1 准备模型文件2.2 修改Backend以加载和运行模型三、关键一步&#xff1a;输出结果的后处理四、运行与验证五、总结与展望一、概述 1.1 背景介绍&#xff1a;从“训练”到“部署…

【动态规划 | 多状态问题】动态规划求解多状态问题

算法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;斐波那契数列模型路径问题多状态问题通常涉及多个决策点和状态转换&#xff0c;解决起来复杂且计算量大。动态规划作为一种强大的算法工具&#xff0c;能够通过将问题分解为子问题并逐步求解&#xff0c;显著提…

【HTTP】防XSS+SQL注入:自定义HttpMessageConverter过滤链深度解决方案

防XSSSQL注入&#xff1a;自定义HttpMessageConverter过滤链深度解决方案一、安全威胁模型分析二、自定义HttpMessageConverter架构设计2.1 技术栈组成三、完整实现代码3.1 安全过滤工具类3.2 自定义HttpMessageConverter3.3 Spring安全配置四、深度防御增强方案4.1 SQL注入参数…

学习游戏制作记录(冻结敌人时间与黑洞技能)7.30

1.实现剑击中敌人时冻结敌人时间Enemy脚本&#xff1a;public float defaultMoveSpeed;//默认速度defaultMoveSpeed moveSpeed;//Awake&#xff08;&#xff09;中设置public virtual void FreezeTime(bool _timeFreeze)//冻结设置函数{if (_timeFreeze){moveSpeed 0;anim.sp…

【数据结构】真题 2016

待补充已知表头元素为c的单链表在内存中的存储状态如下表所示地址元素链接地址1000Ha1010H1004Hb100CH1008Hc1000H100CHdNULL1010He1004H1014H现将f存放于1014H处并插入到单链表中&#xff0c;若f在逻辑上位于a和e之间&#xff0c;则a, e, f的“链接地址”依次是&#xff08; &…

双线串行的 “跨界对话”:I2C 与 MDIO 的异同解析

在电子系统设计中,串行总线凭借其精简的信号线数量和灵活的拓扑结构,成为芯片间通信的主流选择。I2C(Inter-Integrated Circuit)和 MDIO(Management Data Input/Output)作为两种典型的双线串行总线,虽同属低速信号范畴,却在各自的应用领域扮演着不可替代的角色。本文将…

算法精讲:二分查找(二)—— 变形技巧

&#x1f3af; 算法精讲&#xff1a;二分查找&#xff08;二&#xff09;—— 变形技巧 &#x1f50d; 友情提示&#xff1a;&#xff1a;本小节含高能代码片段 &#x1f964; 阅读前请确保已掌握基础二分原理与实现代码片段可能包含不同程度的变形&#xff0c;请根据实际情况选…

两个程序配合实现了基于共享内存和信号量的进程间通信,具体说明如下:

第一个程序&#xff1a;共享内存读取程序&#xff08;消费者&#xff09;该程序作为消费者&#xff0c;从共享内存中读取数据&#xff0c;通过信号量保证只有当生产者写入数据后才能读取。/*4 - 读共享内存*/ #include<stdio.h> // 标准输入输出库 #inc…

JeecgBoot(1):前后台环境搭建

1 项目介绍 JeecgBoot 是一款基于 Java 的 AI 低代码平台&#xff0c;它采用了 SpringBoot、SpringCloud、Ant Design Vue3、Mybatis 等技术栈&#xff0c;并集成了代码生成器、AI 对话助手、AI 建表、AI 写文章等功能。JeecgBoot 的设计宗旨是实现简单功能零代码开发&#xf…

Nestjs框架: 关于 OOP / FP / FRP 编程

概述 在软件开发过程中&#xff0c;不同的编程范式为我们提供了多样化的思维方式与实现路径它们不仅影响着代码的结构和逻辑组织方式&#xff0c;也深刻影响着项目的可维护性、可扩展性以及团队协作效率 什么是 OOP、FP 和 FRP&#xff1f;首先从三个术语的含义入手 1 &#xf…

elememtor 添加分页功能

各位看官好&#xff0c;最近在忙着使用elementor搭建自己的网站&#xff0c;由于我不是专业的程序员和前端&#xff0c;又没有很多钱去找外包公司实现自己的设计&#xff0c;所以选择了elementor. 总的来说这是一个不错的wordpress 插件&#xff0c;也让我们这种非专业的网站设…

关于“PromptPilot” 之2 -目标系统:Prompt构造器

目标系统&#xff1a;Prompt构造器想法首先&#xff0c;在抽象层对PromptPilot进行封装给出提示词形成过程的全部环节。然后&#xff0c;在 形成一套确定的提示词后再为 小规模试点方案生成一整套开发工具并配套集成开发环境和指南。最后&#xff0c;在小规模试点成功后进行拓展…

短剧小程序系统开发:重塑影视内容消费格局

在数字化浪潮的推动下&#xff0c;影视内容消费正经历着深刻的变革。短剧小程序系统开发作为这一变革的重要力量&#xff0c;正在重塑影视内容消费的格局&#xff0c;为用户带来更加个性化、便捷化的观影体验。传统影视内容消费往往受到时间和空间的限制&#xff0c;用户需要前…

一文掌握最新版本Monocle3单细胞轨迹(拟时序)分析

许多大佬的软件想要构建一个大而美的生态&#xff0c;从 monocle2 开始就能做单细胞的质控、降维、分群、注释这一系列的分析&#xff0c;但不幸的是我们只知道 monocle 系列还是主要做拟时序分析&#xff0c;一方面是因为 Seurat 有先发优势&#xff0c;出名要趁早&#xff0c…

spark入门-helloword

我们学习编程语言的时候&#xff0c;第一个程序就是打印一下 “hello world” &#xff0c;对于大数据领域的第一个任务则是wordcount。那我们就开始我们的第一个spark任务吧&#xff01; 下载spark 官方下载地址&#xff1a;Apache Download Mirrors 下载完毕以后&#xff0c…

雷达系统设计学习:自制6GHz FMCW Radar

国外大神自制6GHZ FMCW Radar开源项目: https://github.com/Ttl/fmcw3 引言 之前我做过一个简单的调频连续波&#xff08;FMCW&#xff09;雷达&#xff0c;能够探测到100米范围内人体大小的物体。虽然它确实能用&#xff0c;但由于预算有限&#xff0c;还有很大的改进空间。 …

系统选择菜单(ubuntu grub)介绍

好的&#xff0c;我们来详细解释一下什么是Ubuntu的GRUB菜单。 简单来说&#xff0c;GRUB菜单是您电脑启动时看到的第一个交互界面&#xff0c;它就像一个“系统选择”菜单&#xff0c;让您决定接下来要启动哪个操作系统或进入哪种模式。详细解释 1. GRUB是什么&#xff1f; GR…