【LeetCode 题解】算法:4.寻找两个正序数组的中位数

news2025/3/26 10:50:45

1. 引言:挑战 LeetCode 经典算法题

在算法这片广袤无垠的天地里,一道道经典题目宛如夜空中熠熠生辉的星辰,持续吸引着开发者们投身其中,不断探索。今天,我们继续将目光聚焦于 LeetCode 平台上一道极具代表性的题目:如何运用 Java 语言,精确找出两个正序数组的中位数,并且要将算法的时间复杂度严格控制在 (O(log (m + n))) 。这一挑战过程就像一场充满惊险与刺激的冒险,其间思维的火花不断碰撞,探索的乐趣贯穿始终,让我们一同开启这段精彩绝伦的奇妙之旅。

2. 问题拆解:正序数组中位数探寻任务

题目明确给出两个大小分别为 m 和 n 的正序数组 nums1 与 nums2 。我们的核心任务,便是毫无差错地找出这两个数组合并之后的中位数。形象地来讲,这就如同在一堆已经依照顺序排列整齐的拼图碎片里,精准定位到处于最中间位置的那一块(若总碎片数为偶数,则是中间两块的平均值),这个中位数对于把握整个数据集合的中心趋势起着至关重要的作用。

2.1 示例解析:直观理解中位数计算

  • 示例一:当输入为 nums1 = [1, 3] ,nums2 = [2] 时,输出结果为 2.00000 。想象一下,有三个数字小朋友依次站成一排,顺序是 1、2、3 ,站在正中间位置的 2 小朋友,就是我们苦苦寻觅的中位数,它直观地代表了这个小型数字集合的中间水平。

  • 示例二:若输入为 nums1 = [1, 2] ,nums2 = [3, 4] ,输出则是 2.50000 。此时,四个数字小朋友站成一排,顺序为 1、2、3、4 ,而中间位置恰好处于 2 和 3 这两个数字之间。所以,中位数就是这两个数字的平均值,即 (2 + 3) / 2 = 2.5 。这一计算过程,就像是在数字队列中精准地找到了中间的平衡点,巧妙且清晰地反映出数据的集中趋势。

3. 解题思路:巧用二分查找破题

要想实现 (O(log (m + n))) 这般高效的时间复杂度,二分查找这一强大有力的工具无疑是我们的 “秘密武器”。不妨想象一下,你身处一座规模宏大、藏书海量的图书馆,而你需要寻找一本特定的书籍。二分查找就如同赋予了你一种神奇的能力,每一次操作都能够精准地将搜索范围缩小一半,从而迅速锁定目标,极大程度地提升查找效率。

具体到本题当中,我们的解题思路是在较短的那个数组上巧妙施展二分查找的精妙技巧。我们把两个数组视作两块大蛋糕,需要将它们切成左右两部分。在切分的时候,有两个关键要求:其一,左右两部分的元素个数要尽可能相等(若总元素个数为奇数,那就让左边比右边多一个);其二,左边部分的所有元素都必须小于等于右边部分的所有元素。一旦成功完成这样的切分操作,处于中间位置的元素(若总元素个数为偶数,则是中间两个元素的平均值),便是我们梦寐以求的中位数。

4. Java 代码呈现:核心实现逻辑

public class MedianOfTwoSortedArrays {

public double findMedianSortedArrays(int[] nums1, int[] nums2) {

// 确保nums1是较短的数组,这样可以减少二分查找的范围

if (nums1.length > nums2.length) {

return findMedianSortedArrays(nums2, nums1);

}

int m = nums1.length;

int n = nums2.length;

int imin = 0, imax = m, halfLen = (m + n + 1) / 2;

while (imin <= imax) {

// 在nums1上进行二分查找

int i = (imin + imax) / 2;

// 根据i计算nums2上的划分位置

int j = halfLen - i;

if (i < m && nums2[j - 1] > nums1[i]) {

// i太小,需要增大

imin = i + 1;

} else if (i > 0 && nums1[i - 1] > nums2[j]) {

// i太大,需要减小

imax = i - 1;

} else {

// i是完美的划分位置

int maxOfLeft;

if (i == 0) {

// nums1左半部分为空

maxOfLeft = nums2[j - 1];

} else if (j == 0) {

// nums2左半部分为空

maxOfLeft = nums1[i - 1];

} else {

// 取两个数组左半部分的最大值

maxOfLeft = Math.max(nums1[i - 1], nums2[j - 1]);

}

if ((m + n) % 2 == 1) {

// 总元素个数为奇数,中位数就是左半部分的最大值

return maxOfLeft;

}

int minOfRight;

if (i == m) {

// nums1右半部分为空

minOfRight = nums2[j];

} else if (j == n) {

// nums2右半部分为空

minOfRight = nums1[i];

} else {

// 取两个数组右半部分的最小值

minOfRight = Math.min(nums1[i], nums2[j]);

}

// 总元素个数为偶数,中位数是左半部分最大值和右半部分最小值的平均值

return (maxOfLeft + minOfRight) / 2.0;

}

}

// 不会执行到这里

throw new IllegalArgumentException();

}

public static void main(String[] args) {

MedianOfTwoSortedArrays solution = new MedianOfTwoSortedArrays();

int[] nums1 = {1, 3};

int[] nums2 = {2};

System.out.println(solution.findMedianSortedArrays(nums1, nums2));

nums1 = new int[]{1, 2};

nums2 = new int[]{3, 4};

System.out.println(solution.findMedianSortedArrays(nums1, nums2));

}

}

5. 代码逐行剖析:理解每一步操作

5.1 数组长度调整策略

代码一开始,就会细致地比较 nums1 和 nums2 的长度。一旦发现 nums1 的长度大于 nums2 ,便会灵活巧妙地调用自身方法,将两个数组的位置进行互换,以此确保 nums1 始终是较短的那个数组。这一操作就如同在整理书架时,特意把书本数量较少的那一排放在最便于拿取的位置,为后续进行二分查找提供了极大的便利,能够显著缩小查找范围,进而有效提升算法的整体效率。

5.2 二分查找初始化与推进

初始化了多个关键变量,其中 imin 和 imax 就如同两个忠诚的 “哨兵”,精准无误地标记出二分查找的范围边界;而 halfLen 则像是一把特制的 “尺子”,专门用于确定数组划分位置的关键数值。在 while 循环中,通过 (imin + imax) / 2 这一精巧的运算,在 nums1 数组上成功确定划分位置 i 。紧接着,依据 halfLen 迅速计算出 nums2 数组对应的划分位置 j 。这一过程,就仿佛是在两块拼图板上同时精准地寻找分割线,使得左右两边的拼图数量恰到好处,为后续正确划分数组奠定了坚实的基础。

5.3 划分位置动态优化

当 i 取值过小时,就会出现 nums2 左半部分的某个元素大于 nums1 右半部分对应元素的情况。此时,程序会毫不犹豫地将 imin 增大,促使 i 向右移动,这就如同在拼图过程中发现某块碎片位置摆放错误,及时将其调整到正确方向。反之,若 i 取值过大,导致 nums1 左半部分的某个元素大于 nums2 右半部分对应元素,程序则会减小 imax ,让 i 向左移动,通过不断地这样优化划分位置,直至达到理想状态。

5.4 中位数计算与输出

一旦成功找到完美的划分位置 i ,便正式进入计算中位数的关键环节。首先确定左半部分的最大值 maxOfLeft :若 nums1 左半部分为空,那就直接选取 nums2 左半部分的最后一个元素;若 nums2 左半部分为空,则选取 nums1 左半部分的最后一个元素;若两者均不为空,就从两个数组左半部分中选取较大值。若总元素个数为奇数,那么 maxOfLeft 就是我们苦苦追寻的中位数,直接返回该结果,顺利完成任务。若总元素个数为偶数,还需确定右半部分的最小值 minOfRight ,其计算方式与确定 maxOfLeft 类似。最后,通过 (maxOfLeft + minOfRight) / 2.0 这一公式,精准计算出中位数,这就如同找到了拼图中间的关键连接点,将左右两边完美融合,输出最终答案。

6. 复杂度分析:算法效率评估

6.1 时间复杂度

(O(log(min(m, n)))) ,这是因为我们巧妙地将二分查找操作限定在较短的数组上。每次执行二分查找,都如同在迷宫中找到了正确的岔路,能够将搜索范围精准地缩小一半,极大地提高了查找效率,使得算法能够快速朝着目标前进。

6.2 空间复杂度

(O(1)) ,整个算法在执行过程中,仅仅使用了几个固定不变的变量,就如同在一个小巧而精致的工作室里工作,无需占用过多额外空间,充分展现了算法设计的简洁高效,尽显精妙之处。

感谢各位的阅读,后续将持续给大家讲解力扣中的算法题,如果觉得这篇内容对你有帮助,别忘了点赞和关注,后续还有更多精彩的算法解析与你分享!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cesium 自定义路径导航材质

cesium 自定义路径导航纹理图片随便更换&#xff0c;UI 提供设计图片即可达到效果&#xff1b; 打开小马的weix 关注下 搜索“技术链” 回复关键词《《路径》》获取原始代码&#xff1b; 拿到就能用轻松解决&#xff01;帮忙点个关注吧&#xff01;

【江协科技STM32】BKP备寄存器RTC实时时钟(学习笔记)

BKP备寄存器 BKP简介 BKP&#xff08;Backup Registers&#xff09;备份寄存器BKP可用于存储用户应用程序数据。当VDD&#xff08;2.0~3.6V&#xff09;电源被切断&#xff0c;他们仍然由VBAT&#xff08;1.8~3.6V&#xff09;维持供电。当系统在待机模式下被唤醒&#xff0…

卷积神经网络 - 参数学习

本文我们通过两个简化的例子&#xff0c;展示如何从前向传播、损失计算&#xff0c;到反向传播推导梯度&#xff0c;再到参数更新&#xff0c;完整地描述卷积层的参数学习过程。 一、例子一 我们构造一个非常简单的卷积神经网络&#xff0c;其结构仅包含一个卷积层和一个输出…

亮数据爬取API爬取亚马逊电商平台实战教程

前言 在当今数据驱动的商业环境中&#xff0c;企业需要快速、精准地获取互联网上的公开数据以支持市场分析、竞品调研和用户行为研究。然而&#xff0c;传统的手动网页爬取方式面临着诸多挑战&#xff1a;IP封锁、验证码干扰、网站结构频繁变更&#xff0c;以及高昂的运维成本…

[CLS] Token 在 ViT(Vision Transformer)中的作用与实现

[CLS] Token 在 ViT&#xff08;Vision Transformer&#xff09;中的作用与实现 1. 什么是 [CLS] Token&#xff1f; [CLS]&#xff08;classification token&#xff09;是Transformer模型中一个可学习的嵌入向量&#xff0c;最初在 BERT&#xff08;Bidirectional Encoder …

基于网启PXE服务器的批量定制系统平台

项目概述 1.需求 公司新购了一批服务器和台式机&#xff0c;需要为台式机和服务器安装系统&#xff0c;一部分需要安装国产OpenEuler&#xff0c;一部分要求安装CentOS 7.9&#xff0c;同时也要满足定制化需求&#xff0c;即按要求分区安装相应软件。 2.使用开源软件 &…

在本地Windows机器加载大模型并生成内容

本篇演示在本地机器下载和加载大模型并获取AI产生的内容。简单起见&#xff0c;使用的大模型是Qwen2.5-0.5B-Instruct&#xff0c;整个模型的所有文件不到1G。 Qwen2.5-0.5B-Instruct 是阿里巴巴云 QWen 团队基于 Transformer 架构开发的轻量级指令调优语言模型&#xff0c;专…

热门面试题第14天|Leetcode 513找树左下角的值 112 113 路径总和 105 106 从中序与后序遍历序列构造二叉树 (及其扩展形式)以一敌二

找树左下角的值 本题递归偏难&#xff0c;反而迭代简单属于模板题&#xff0c; 两种方法掌握一下 题目链接/文章讲解/视频讲解&#xff1a;https://programmercarl.com/0513.%E6%89%BE%E6%A0%91%E5%B7%A6%E4%B8%8B%E8%A7%92%E7%9A%84%E5%80%BC.html 我们来分析一下题目&#…

【计算机网络】-计算机网络期末复习题复习资料

一、计算机网络体系结构&#xff08;800字&#xff09; 1. OSI参考模型 七层结构&#xff1a;物理层→数据链路层→网络层→传输层→会话层→表示层→应用层 各层核心功能&#xff1a; 物理层&#xff1a;比特流传输&#xff08;如RJ45、光纤接口&#xff09; 数据链路层&…

批归一化(Batch Normalization)与层归一化(Layer Normalization)的区别与联系

文章目录 一、Batch normalization 理论与应用1. 理论解释2. 数值例子 二、Layer normalization 理论与应用1. 理论解释2. 数值例子 三、Layer Normalization 和 Batch Normalization 的区别四、《Transformers without Normalization》笔记 一、Batch normalization 理论与应用…

12届蓝桥杯—货物摆放

货物摆放 题目描述 小蓝有一个超大的仓库&#xff0c;可以摆放很多货物。 现在&#xff0c;小蓝有 nn 箱货物要摆放在仓库&#xff0c;每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向&#xff0c;每箱货物的边都必须严格平行于长、宽、高。 小蓝希望所…

c++进阶--哈希表的实现

大家好&#xff0c;今天我们来学习ubordered_set和unordered_map的底层哈希表。 目录 哈希表实现 1. 哈希概念 1.1 直接定址法 1.2 哈希冲突 1.3 负载因⼦ 1.4 将关键字转为整数 1.5 哈希函数 下面我们介绍几种哈希函数&#xff1a;1.5.1 除法散列法/除留余数法 1.…

颠覆传统:SaaS 品牌如何通过 SEO 策略引爆市场!

SaaS 商业模式提供了令人难以置信的可扩展性和盈利能力——但前提是与正确的营销增长策略相结合。 SaaS 品牌知道&#xff0c;托管基于云的应用程序的成本会随着用户量的增加而降低&#xff0c;因此必须专注于订阅者的快速增长&#xff0c;以保持竞争力并降低成本。 许多 CMO…

特殊行车记录仪DAT视频丢失的恢复方法

行车记录仪是一种常见的车载记录仪&#xff0c;和常见的“小巧玲珑”的行车记录仪不同&#xff0c;一些特种车辆使用的记录仪的外观可以用“笨重”来形容。下边我们来看看特种车载行车记录仪删除文件后的恢复方法。 故障存储: 120GB存储设备/文件系统:exFAT /簇大小:128KB 故…

数据库中不存在该字段

mybatisplus 定义的类中某些字段是数据库里面没有的&#xff0c;我们可用tablefield(existfalse)来注解&#xff0c;演示如下&#xff1a;

吾爱出品,文件分类助手,高效管理您的 PC 资源库

在日常使用电脑的过程中&#xff0c;文件杂乱无章常常让人感到困扰。无论是桌面堆积如山的快捷方式&#xff0c;还是硬盘中混乱的音频、视频、文档等资源&#xff0c;都急需一种高效的整理方法。文件分类助手应运而生&#xff0c;它是一款文件管理工具&#xff0c;能够快速、智…

关于瑞芯微开发工具(RKDevTool)刷机下载Boot失败原因的研究

昨天发了文章《网心云OEC/OEC-turbo刷机问题——刷机教程、救砖方法、技术要点及下载boot失败异常解决尝试》&#xff0c;其中有关于刷机各种问题的一些解决方法。 网心云OEC/OEC-turbo刷机问题——刷机教程、救砖方法、技术要点及下载boot失败异常解决尝试-CSDN博客文章浏览阅…

web爬虫笔记:js逆向案例十一 某数cookie(补环境流程)

web爬虫笔记:js逆向案例十一 某数cookie(补环境流程) 一、获取网页数据请求流程 二、目标网址、cookie生成(逐步分析) 1、目标网址:aHR0cHM6Ly9zdWdoLnN6dS5lZHUuY24vSHRtbC9OZXdzL0NvbHVtbnMvNy9JbmRleC5odG1s 2、快速定位入口方法 1、通过脚本监听、hook_cookie等操作可…

Excel多级联动下拉菜单的自动化设置(使用Python中的openpyxl模块)

1 主要目的 在Excel中&#xff0c;经常会遇到需要制作多级联动下拉菜单的情况&#xff0c;要求单元格内填写的内容只能从指定的多个选项中进行选择&#xff0c;并且需要设置多级目录&#xff0c;其中下级目录的选项内容要根据上级目录的填写内容确定&#xff0c;如下图所示&am…

excalidraw画图工具——背景画布有无格子设置

服啦找了大半天&#xff0c;愣是没找到 toggle grid &#xff1a; 切换格子… Excalidraw的背景格子 只要右键&#xff0c;将这个勾取消就好了&#xff1f;