一、文章标题

LeetCode 004. 寻找两个正序数组的中位数 - 二分切分与分治详解

二、文章内容

1. 题目概述
  • 题目描述:给定两个已按非降序排列的整数数组 nums1、nums2,设它们长度分别为 m 和 n,要求返回这两个数组合并后有序序列的中位数。整体期望时间复杂度为 O(log(m+n))。当总长度为偶数时,中位数为中间两个数的平均值(返回 double)。数组可能为空,但不会同时为空(若实现中遇到同时为空需返回默认值)。
  • 原题链接:https://leetcode.cn/problems/median-of-two-sorted-arrays/
  • 难度等级:Hard
  • 相关标签:数组、二分查找、分治、双指针
2. 文章目录

目录

  1. 题目概述
  2. 解题思路
  3. 算法详解
    • 3.1 解法一:双指针线性扫描到中位数
    • 3.2 解法二:二分切分(最优)
  4. 解法对比
  5. 最优解推荐
3. 解题思路
  • 问题分析:
    • 输入:两个已排序的整型数组 nums1、nums2。
    • 输出:合并后序列的中位数(double)。
    • 中位数定义:
      • 若 m+n 为奇数,中位数为第 (m+n)/2(0 基)处的元素。
      • 若 m+n 为偶数,中位数为第 (m+n)/2 - 1 与 (m+n)/2 两个元素均值。
  • 核心难点:
    • 在不真正合并数组的前提下,以 O(log(m+n)) 时间找到中位数。
    • 复杂边界处理:空数组、分割端点在数组两侧、奇偶长度处理、整型转 double。
  • 解题方向:
    1. 线性合并/扫描到中位数位置(O(m+n),实现直观,作为兜底)。
    2. 分治/找第 k 小(每轮丢弃 k/2 个元素,O(log(m+n)))。
    3. 二分切分(只对较短数组二分,构造左右两半满足有序关系,O(log(min(m,n))),最优)。
4. 算法详解

解法一:双指针线性扫描到中位数

算法原理

  • 核心思想:像归并排序的合并过程一样,用两根指针从头扫描两个有序数组,不必真的合并,只需走到中位数所在下标就停止。
  • 适用场景:当不强求 O(log(m+n))、或用作对拍与兜底实现时非常好用。

具体实现

  • 步骤1:准备两个指针 i、j 指向 nums1、nums2 开始位置,准备计数 idx 表示当前合并到的下标。
  • 步骤2:每次取两个指针中较小的元素作为“当前值”,并向前推进对应指针,直到走到右侧中位数下标 mid2。
  • 步骤3:根据总长度奇偶,返回 curr 或 (prev+curr)/2.0。

复杂度分析

  • 时间复杂度:O(m+n),最坏需要扫描完所有元素。
  • 空间复杂度:O(1),只用到常数额外变量。

Java代码实现

class Solution {/*** 线性扫描到中位数位置的解法(O(m+n))。* 注意:为讲解清晰,方法名与最优解区分;在 LeetCode 提交时可将最优解方法名改为题目要求的方法名。*/public double findMedianSortedArraysLinear(int[] nums1, int[] nums2) {// 将 null 视作空数组,避免空指针if (nums1 == null) nums1 = new int[0];if (nums2 == null) nums2 = new int[0];int m = nums1.length, n = nums2.length;int total = m + n;// 题目一般保证不会同时为空;为健壮性,这里返回默认值 0.0if (total == 0) {return 0.0;}// 左、右中位数的目标下标(0 基)int mid1 = (total - 1) / 2; // 左中位数int mid2 = total / 2;       // 右中位数int i = 0, j = 0;  // 两个数组的扫描指针int idx = -1;      // 已经“取出”的元素个数 - 1int prev = 0;      // 上一个取出的值(用于偶数总长度)int curr = 0;      // 当前取出的值// 扫描直到到达右中位数位置while (idx < mid2) {prev = curr; // 记录上一个值// 取较小值推进(当某一数组用尽时,取另一数组)if (i < m && (j >= n || nums1[i] <= nums2[j])) {curr = nums1[i++];} else if (j < n) {curr = nums2[j++];}idx++;}// 奇偶分别处理if ((total & 1) == 1) {return curr; // 奇数长度,中位数就是当前值} else {return (prev + curr) / 2.0; // 偶数长度,取均值}}
}

解法二:二分切分(最优)

算法原理

  • 基本思想:只对较短的数组进行二分,在两个数组上找到一个“切分点对” (i, j),使得:
    • 左半部分长度等于右半部分长度(或只多 1),即 i + j = (m + n + 1) / 2;
    • 左半最大值 ≤ 右半最小值,即 max(A[i-1], B[j-1]) ≤ min(A[i], B[j])。
  • 一旦上述条件成立:
    • 若总长度为奇数,中位数是左半最大值;
    • 若为偶数,中位数是左半最大值与右半最小值的平均。
  • 适用场景:追求最优时间复杂度,面试高频且边界清晰的标准解。

具体实现

  • 步骤1:确保对更短的数组二分,令 A 为短数组,B 为长数组。
  • 步骤2:在 A 的 [0…m] 区间二分 i,令 j = (m+n+1)/2 - i。
  • 步骤3:检查是否满足分割条件;若 A[i-1] > B[j],说明 i 偏大,收缩右边;若 B[j-1] > A[i],说明 i 偏小,收缩左边;否则命中答案。

复杂度分析

  • 时间复杂度:O(log(min(m,n))),只在短数组长度范围内二分。
  • 空间复杂度:O(1),常数额外空间。

Java代码实现

class Solution {/*** 最优解:二分切分,时间复杂度 O(log(min(m,n))),空间 O(1)。* 若两个数组都为空则返回 0.0 作为默认值,避免抛异常。*/public double findMedianSortedArrays(int[] nums1, int[] nums2) {// 将 null 视作空数组,避免空指针if (nums1 == null) nums1 = new int[0];if (nums2 == null) nums2 = new int[0];// 始终让 A 为较短数组,B 为较长数组int[] A = nums1.length <= nums2.length ? nums1 : nums2;int[] B = (A == nums1) ? nums2 : nums1;int m = A.length, n = B.length;// 边界:两个都为空,返回默认值if (m + n == 0) {return 0.0;}int left = 0, right = m; // 在 A 的切分位置范围 [0..m] 上二分int half = (m + n + 1) / 2; // 左半部分应包含的元素个数while (left <= right) {int i = left + (right - left) / 2; // A 的切分点int j = half - i;                  // B 的切分点,使得左半长度满足要求// 处理边界元素,越界时使用极小/极大的“哨兵”思想(用比较逻辑避免实际越界)int Aleft  = (i == 0) ? Integer.MIN_VALUE : A[i - 1];int Aright = (i == m) ? Integer.MAX_VALUE : A[i];int Bleft  = (j == 0) ? Integer.MIN_VALUE : B[j - 1];int Bright = (j == n) ? Integer.MAX_VALUE : B[j];// 检查是否满足切分正确:左边最大 <= 右边最小if (Aleft <= Bright && Bleft <= Aright) {// 命中:根据奇偶直接计算中位数if (((m + n) & 1) == 1) {// 奇数:中位数是左边最大值int leftMax = Math.max(Aleft, Bleft);return (double) leftMax;} else {// 偶数:中位数是 左边最大 与 右边最小 的均值int leftMax = Math.max(Aleft, Bleft);int rightMin = Math.min(Aright, Bright);return (leftMax + rightMin) / 2.0;}} else if (Aleft > Bright) {// A 的左边太大,i 需要左移right = i - 1;} else {// Bleft > Aright,i 需要右移left = i + 1;}}// 理论上一定能在循环内返回;为健壮性返回默认值return 0.0;}
}
5. 解法对比与总结
解法时间复杂度空间复杂度优点缺点适用场景
双指针线性扫描到中位数O(m+n)O(1)实现直观、边界简单、易调试不满足题目要求的对数级时间数据量不大、或作为兜底与对拍
二分切分(最优)O(log(min(m,n)))O(1)满足最优时间、无需额外空间、思路标准边界处理细节较多,上手需练习面试高频、追求最优性能

最优解推荐:二分切分。其时间复杂度 O(log(min(m,n))),空间 O(1),能严格满足题目对数级要求,且是工业界与面试中的标准写法,值得熟练掌握。

三、文章标签

算法,二分查找,LeetCode,困难,数组,双指针,分治

四、文章简述

本题考察两个有序数组的中位数,给出线性双指针与二分切分两种方案。重点讲解边界处理、奇偶长度与复杂度分析,附带完整 Java 实现与注释,含对比与选型建议,适合面试与算法进阶读者。

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

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

相关文章

预闪为什么可以用来防红眼?

打闪拍照红眼产生的原因 预闪可以用来防红眼&#xff0c;是基于人眼的生理特性和红眼现象的产生原理。在光线较暗时&#xff0c;人眼的瞳孔会放大。当使用闪光灯拍摄时&#xff0c;如果直接进行高强度闪光&#xff0c;由于瞳孔来不及缩小&#xff0c;闪光灯的光线会反射在眼球血…

Python程序使用了Ffmpeg,结束程序后,文件夹中仍然生成音频、视频文件

FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec&#xff0c;为了保证高可移植性和编解码质量&#xff0…

模块与包的导入

077-模块-06-模块搜索顺序_哔哩哔哩_bilibili 080-包-01-包的概念以及建立包的方式_哔哩哔哩_bilibili 088-文件操作-01-文件操作套路以及Python中的对应函数和方法_哔哩哔哩_bilibili 注&#xff1a; 1.import math和 from math import *区别 2. 模块&#xff08;Module…

Docker Compose 多种安装方式 (Alibaba Cloud Linux 3 环境)

Docker Compose 多种安装方式&#xff0c;适用于不同场景&#xff08;如依赖系统包管理器、使用 Python 工具链、集成 Docker 插件等&#xff09;。以下是常见的方案&#xff0c;尤其针对 Alibaba Cloud Linux 3 环境适配&#xff1a; 一、二进制包安装&#xff08;推荐&#…

Dubbo3序列化安全机制导致的一次生产故障

前言 记录一次 Dubbo 线上故障排查和原因分析。 线上 Dubbo 消费者启动有错误日志如下&#xff0c;但是不影响服务启动。 java.lang.TypeNotPresentException: Type org.example.model.ThirdParam not present ... Caused by: java.lang.ClassNotFoundException: org.example.m…

centos7 docker离线安装

介绍 本文主要讲了如何在完全没网的情况下安装docker&#xff08;适合于高网络安全要求的企业&#xff09; 本文适用的centos版本&#xff1a; [root0001 temp]# cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core) 采用docker in docker下载依赖 实际试验后&…

东京本社招聘 | 财务负责人 多个日本IT岗位(Java/C++/Python/AWS 等),IT营业同步招募

大家好&#xff0c;本期为大家带来我司在东京GSD本社及其他会社千叶地区的招聘岗位。 涵盖 财务负责人、Java开发工程师、数据中心维护工程师、项目经理、IT营业 等多个职位。 欢迎有志之士加入&#xff01;&#x1f539; 财务负责人&#xff08;東京本社&#xff09;工作内容日…

四数之和

目录 一&#xff1a;题目链接 二&#xff1a;题目思路 三&#xff1a;代码实现 一&#xff1a;题目链接 理解题目需要注意&#xff0c;如果两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#xff0c;选择其中一个四元组即可。比如 [ 0 , 1 , 0 , 2] 和 [ 1 , …

【序列晋升】29 Spring Cloud Task 微服务架构下的轻量级任务调度框架

Spring Cloud Task作为微服务架构中的轻量级任务调度框架&#xff0c;为开发人员提供了一种构建短生命周期微服务任务的便捷方式。它允许开发者快速创建、执行和管理一次性任务或短期批处理作业&#xff0c;任务执行完成后自动关闭以释放系统资源&#xff0c;避免了传统长期运行…

【1分钟速通】 HTML快速入门

HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09; 是构建网页的基础语言。它通过 标签&#xff08;Tag&#xff09; 来描述网页的结构和内容&#xff0c;常与 CSS&#xff08;负责样式 – <style></style>&#xff09;和 JavaScr…

【GeoServer】WMS GetFeatureInfo URL 逐个参数解释

我来把你构造的这个 WMS GetFeatureInfo URL 逐个参数解释一下&#xff0c;方便你理解&#xff1a;http://127.0.0.1:8090/geoserver/xxxx/wms? SERVICEWMS& VERSION1.1.1& REQUESTGetFeatureInfo& QUERY_LAYERSloess:yourLayer& LAYERSloess:yourLayer& …

OBS直播教程:点歌直播间怎么弄?直播点歌用什么软件?

OBS直播教程&#xff1a;点歌直播间怎么弄&#xff1f;直播点歌用什么软件&#xff1f; 第一步&#xff1a;安装OBS直播软件&#xff0c;如果你电脑已经安装了OBS&#xff0c;请直接看第二步 OBS直播软件下载地址①&#xff1a; https://d.obscj.com/obs-Studio-29.1.3-Full-…

【数据库】Redis详解:内存数据库与缓存之王

什么是Redis&#xff1f; Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、基于内存的数据结构存储系统&#xff0c;可以用作数据库、缓存和消息代理。它支持多种数据结构&#xff0c;如字符串、哈希、列表、集合、有序集合等&#xff0c;具有极高的性能和…

【iOS】 单例模式

1. 认识单例模式首先让我们先看下关于单例模式的定义&#xff08;来自于《设计模式》(Addison-Wesley,1994)&#xff09;一个类有且仅有一个实例&#xff0c;并且自行实例化向整个系统提供。如果说每一个人都是一个类&#xff0c;那么从他出生开始&#xff0c;他就是生活中的唯…

多目标轮廓匹配

前面我们使用模板匹配&#xff0c;得到的结果都是一个图&#xff0c;那么如果我们图片中有许多我们的目标&#xff0c;那么该如何找出来呢&#xff1f;如上我们图片中有许多箭头和我们的模板一致&#xff0c;只不过方向不对&#xff0c;那么该如何匹配呢&#xff1f;图片和模板…

【C++】简单介绍lambda表达式

各位大佬好&#xff0c;我是落羽&#xff01;一个坚持不断学习进步的学生。 如果您觉得我的文章还不错&#xff0c;欢迎多多互三分享交流&#xff0c;一起学习进步&#xff01; 也欢迎关注我的blog主页: 落羽的落羽 文章目录一、 什么是lambda表达式二、 表达式语法三、lambd…

磁共振成像原理(理论)4:自由进动和弛豫 (Free Precession and Relaxation)

当磁化自旋系统被射频脉冲扰动而偏离其热平衡态后&#xff0c;一旦移除外部激励并给予足够时间&#xff0c;系统将根据热力学定律返回平衡态。这一过程包含三个特征现象&#xff1a; (a) 自由进动——宏观磁化矢量 (M⃗\vec{M}M) 绕( B0⃗\vec {B_0}B0​​ )场的进动&#xff1…

ubuntu 20.04 安装spark

安装openjdk21 下载 wget https://download.java.net/openjdk/jdk21/ri/openjdk-2135_linux-x64_bin.tar.gz解压 tar -xvf openjdk-2135_linux-x64_bin.tar.gzsudo mv jdk-21/ /opt/jdk-21/设置环境变量 echo export JAVA_HOME/opt/jdk-21 | sudo tee /etc/profile.d/java2…

第三方区块链应用测评:【多签钱包合约安全评估_阈值签名机制与私钥存储安全性测试】

阈值签名机制安全测试密码学审计 采用门限签名方案&#xff08;TSS&#xff09;的多签钱包需验证其阈值BLS签名或ECDSA签名算法的正确性。测试重点包括&#xff1a;分布式密钥生成&#xff08;DKG&#xff09;过程的保密性&#xff08;无密钥信息泄露&#xff09;、签名碎片验证…

大模型处理长文档的挑战和解决方案?

当前&#xff0c;AI 应用正处于极速发展阶段&#xff0c;大语言模型&#xff08;LLM&#xff09;与检索增强生成&#xff08;RAG&#xff09;系统已成为构建智能问答、知识管理等高阶 AI 应用的核心引擎&#xff0c;被广泛应用于金融分析、学术研究、企业合规等多个领域。然而&…