【LeetCode 题解】算法:4.寻找两个正序数组的中位数
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)) ,整个算法在执行过程中,仅仅使用了几个固定不变的变量,就如同在一个小巧而精致的工作室里工作,无需占用过多额外空间,充分展现了算法设计的简洁高效,尽显精妙之处。
感谢各位的阅读,后续将持续给大家讲解力扣中的算法题,如果觉得这篇内容对你有帮助,别忘了点赞和关注,后续还有更多精彩的算法解析与你分享!
相关文章:
【LeetCode 题解】算法:4.寻找两个正序数组的中位数
1. 引言:挑战 LeetCode 经典算法题 在算法这片广袤无垠的天地里,一道道经典题目宛如夜空中熠熠生辉的星辰,持续吸引着开发者们投身其中,不断探索。今天,我们继续将目光聚焦于 LeetCode 平台上一道极具代表性的题目&am…...
基于 SGLang 部署 Qwen2.5 7B 模型
本文将详细介绍如何使用 SGLang 快速部署 Qwen2.5 7B 模型,并深入探讨 SGLang 的关键性能优化技术,以及预期可以达到的延迟和吞吐量。 1. SGLang 框架介绍 SGLang 旨在解决 LLM 服务中的核心挑战: 高延迟: LLM 推理通常需要较长的计算时间,导致响应延迟高。低吞吐量: 由…...
Cesium 自定义路径导航材质
cesium 自定义路径导航纹理图片随便更换,UI 提供设计图片即可达到效果; 打开小马的weix 关注下 搜索“技术链” 回复关键词《《路径》》获取原始代码; 拿到就能用轻松解决!帮忙点个关注吧!...
JDBC 连接字连接 KingbaseES支持主从负载均衡参数说明。
JDBC 连接字符串是用于连接 KingbaseES(人大金仓数据库)的,支持主从负载均衡。让我们逐一解析各个参数的作用,并探讨如何调整到最优。 参数解析 jdbc:kingbase8://10.10.14.19:54321/xxx_onlinejdbc:kingbase8://:指定…...
Java运行时的堆、栈和方法区
目录 1. 堆(Heap)存储内容与线程关系 2. 栈(Stack)存储内容与线程关系 3. 方法区(Method Area)存储内容与线程关系变动 1. 堆(Heap) 存储内容 对象实例(对象实例的全部数…...
【江协科技STM32】BKP备寄存器RTC实时时钟(学习笔记)
BKP备寄存器 BKP简介 BKP(Backup Registers)备份寄存器BKP可用于存储用户应用程序数据。当VDD(2.0~3.6V)电源被切断,他们仍然由VBAT(1.8~3.6V)维持供电。当系统在待机模式下被唤醒࿰…...
卷积神经网络 - 参数学习
本文我们通过两个简化的例子,展示如何从前向传播、损失计算,到反向传播推导梯度,再到参数更新,完整地描述卷积层的参数学习过程。 一、例子一 我们构造一个非常简单的卷积神经网络,其结构仅包含一个卷积层和一个输出…...
亮数据爬取API爬取亚马逊电商平台实战教程
前言 在当今数据驱动的商业环境中,企业需要快速、精准地获取互联网上的公开数据以支持市场分析、竞品调研和用户行为研究。然而,传统的手动网页爬取方式面临着诸多挑战:IP封锁、验证码干扰、网站结构频繁变更,以及高昂的运维成本…...
[CLS] Token 在 ViT(Vision Transformer)中的作用与实现
[CLS] Token 在 ViT(Vision Transformer)中的作用与实现 1. 什么是 [CLS] Token? [CLS](classification token)是Transformer模型中一个可学习的嵌入向量,最初在 BERT(Bidirectional Encoder …...
基于网启PXE服务器的批量定制系统平台
项目概述 1.需求 公司新购了一批服务器和台式机,需要为台式机和服务器安装系统,一部分需要安装国产OpenEuler,一部分要求安装CentOS 7.9,同时也要满足定制化需求,即按要求分区安装相应软件。 2.使用开源软件 &…...
Reactor/Epoll为什么可以高性能?
在 Reactor 模式中使用 epoll_wait 实现低 CPU 占用率的核心原理是 事件驱动的阻塞等待机制,而非忙等待。以下通过分步骤解析其工作原理和性能优势: void network_thread() {int epoll_fd epoll_create1(0);epoll_event events[MAX_EVENTS];// 添加U…...
-JavaEE 应用Servlet 路由技术JDBCMybatis 数据库生命周期
#JavaEE-HTTP-Servlet& 路由 & 周期 参考: https://blog.csdn.net/qq_52173163/article/details/121110753 1 、解释 Servlet 是运行在 Web 服务器或应用服务器上的程序 , 它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数…...
在本地Windows机器加载大模型并生成内容
本篇演示在本地机器下载和加载大模型并获取AI产生的内容。简单起见,使用的大模型是Qwen2.5-0.5B-Instruct,整个模型的所有文件不到1G。 Qwen2.5-0.5B-Instruct 是阿里巴巴云 QWen 团队基于 Transformer 架构开发的轻量级指令调优语言模型,专…...
热门面试题第14天|Leetcode 513找树左下角的值 112 113 路径总和 105 106 从中序与后序遍历序列构造二叉树 (及其扩展形式)以一敌二
找树左下角的值 本题递归偏难,反而迭代简单属于模板题, 两种方法掌握一下 题目链接/文章讲解/视频讲解: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 我们来分析一下题目&#…...
shopify跨境电商行业前景与规模
Shopify跨境电商行业前景与规模分析 一、行业背景 Shopify 是一个全球知名的电子商务平台,它为小型企业到大型企业提供了创建和管理在线商店的工具。近年来,随着全球化进程的加快以及互联网技术的发展,跨境电商已经成为国际贸易的重要组成部…...
【计算机网络】-计算机网络期末复习题复习资料
一、计算机网络体系结构(800字) 1. OSI参考模型 七层结构:物理层→数据链路层→网络层→传输层→会话层→表示层→应用层 各层核心功能: 物理层:比特流传输(如RJ45、光纤接口) 数据链路层&…...
游戏中的碰撞检测算法
参考博客Sort, sweep, and prune: Collision detection algorithms...
批归一化(Batch Normalization)与层归一化(Layer Normalization)的区别与联系
文章目录 一、Batch normalization 理论与应用1. 理论解释2. 数值例子 二、Layer normalization 理论与应用1. 理论解释2. 数值例子 三、Layer Normalization 和 Batch Normalization 的区别四、《Transformers without Normalization》笔记 一、Batch normalization 理论与应用…...
12届蓝桥杯—货物摆放
货物摆放 题目描述 小蓝有一个超大的仓库,可以摆放很多货物。 现在,小蓝有 nn 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。 小蓝希望所…...
c++进阶--哈希表的实现
大家好,今天我们来学习ubordered_set和unordered_map的底层哈希表。 目录 哈希表实现 1. 哈希概念 1.1 直接定址法 1.2 哈希冲突 1.3 负载因⼦ 1.4 将关键字转为整数 1.5 哈希函数 下面我们介绍几种哈希函数:1.5.1 除法散列法/除留余数法 1.…...
颠覆传统:SaaS 品牌如何通过 SEO 策略引爆市场!
SaaS 商业模式提供了令人难以置信的可扩展性和盈利能力——但前提是与正确的营销增长策略相结合。 SaaS 品牌知道,托管基于云的应用程序的成本会随着用户量的增加而降低,因此必须专注于订阅者的快速增长,以保持竞争力并降低成本。 许多 CMO…...
【数据库发展史】
数据库的发展历史可以追溯到20世纪50年代,随着计算机技术的进步和数据管理需求的演变,数据库系统经历了多个阶段的变革。以下是数据库技术的主要发展阶段: 1. 前数据库时代(1950年代前) 手工管理:数据通过…...
HTTP 核心知识点整理
1. HTTP 基础 定义:HTTP(HyperText Transfer Protocol)是应用层协议,基于 请求-响应模型,用于客户端(浏览器)与服务器之间的通信。特点: 无状态:每次请求独立&a…...
从AEC-Q100看车规芯片的可靠性设计要点
引言 随着汽车电子化、智能化的飞速发展,汽车电子控制系统对芯片的可靠性提出了极为严苛的要求。AEC-Q100是汽车电子委员会(Automotive Electronics Council)制定的车规级芯片可靠性标准,旨在确保芯片能够在复杂多变的汽车环境中…...
陕西安全员A证考试的报名流程是什么?
陕西安全员 A 证考试报名流程如下: 进入报名系统:登录陕西省建筑工程施工企业安全管理人员及特种作业人员考试报名系统。首次使用需点击 “特种作业人员注册”,进入个人注册界面。注册账号:输入身份证号、登录密码,并…...
特殊行车记录仪DAT视频丢失的恢复方法
行车记录仪是一种常见的车载记录仪,和常见的“小巧玲珑”的行车记录仪不同,一些特种车辆使用的记录仪的外观可以用“笨重”来形容。下边我们来看看特种车载行车记录仪删除文件后的恢复方法。 故障存储: 120GB存储设备/文件系统:exFAT /簇大小:128KB 故…...
PAT乙级1007
常规解法 #include <iostream> using namespace std;// 判断一个数是否为素数的函数 bool isprime(int a) {// 遍历 2 到 sqrt(a) 之间的数,判断 a 是否能被它们整除for (int i 2; i * i < a; i) {if (a % i 0) // 如果能整除,说明 a 不是素…...
数据库中不存在该字段
mybatisplus 定义的类中某些字段是数据库里面没有的,我们可用tablefield(existfalse)来注解,演示如下:...
吾爱出品,文件分类助手,高效管理您的 PC 资源库
在日常使用电脑的过程中,文件杂乱无章常常让人感到困扰。无论是桌面堆积如山的快捷方式,还是硬盘中混乱的音频、视频、文档等资源,都急需一种高效的整理方法。文件分类助手应运而生,它是一款文件管理工具,能够快速、智…...
关于瑞芯微开发工具(RKDevTool)刷机下载Boot失败原因的研究
昨天发了文章《网心云OEC/OEC-turbo刷机问题——刷机教程、救砖方法、技术要点及下载boot失败异常解决尝试》,其中有关于刷机各种问题的一些解决方法。 网心云OEC/OEC-turbo刷机问题——刷机教程、救砖方法、技术要点及下载boot失败异常解决尝试-CSDN博客文章浏览阅…...
