【LeetCode】4,寻找两个正序数组中的中位数

题目地址
B站那个官方解答视频实在看不懂,我就根据他那个代码和自己的理解写一篇文章

1. 基本思路

在只有一个有序数组的时候,中位数把数组分割成两个部分。中位数的定义:中位数,又称中点数,中值。中位数是按顺序排列的一组数据中居于中间位置的数,即在这组数据中,有一半的数据比他大,有一半的数据比他小,如果数据个数为奇数的时候,则排序后的数据最中间的数是中位数,如果数据个数为偶数的时候,则排序后的数据最中间的两个数的均值称为中位数。
根据中位数的定义,我们要分数组长度为奇数和偶数进行讨论:
(1)首先,将数组一分为二,数组长度为偶数的时候,中位数有两个,其中一个是左边数组的最大值,另一个是右边数组的最小值。

数组长度为奇数的时候,中位数有1个,不妨设中位数分到左边数组。

在两个有序数组的时候,我们仍然可以把两个数组分别按照上面的规则分割为两个部分(注意是将两个数组排成两行然后再对这个整体分割,不是单独分割去分割两个数组中的每一个数组)。
我们使用一条分割线把两个数组分别分割成两部分:
(1)如果两个数组的长度之和为偶数,则让红线左边和右边的元素个数相等;如果两个数组的长度之和为奇数,则让红线左边元素的个数比右边元素的个数多1个;
(2)红线左边的所有元素的值 ≤ \le 红线右边的所有元素的值;
那么中位数就一定只与红线两侧的元素有关,确定这条红线的位置使用二分查找。

优化第1个条件
假设数组1的长度为 m m m,数组2的长度为 n n n
m + n m+n m+n为偶数的时候,左侧数组长度为 m + n 2 \frac{m+n}{2} 2m+n
m + n m+n m+n为奇数的时候,由于我们之前假设中位数被分到左边,则左侧数组长度为 m + n + 1 2 \frac{m+n+1}{2} 2m+n+1(即向上取整)
由于整数除法是向下取整,则可以将当 m + n m+n m+n为偶数的时候,左侧数组长度等效为 m + n + 1 2 \frac{m+n+1}{2} 2m+n+1
因此,左侧数组长度可以合并为 m + n + 1 2 \frac{m+n+1}{2} 2m+n+1
优化第2个条件
为了保持红线左边的所有元素的值 ≤ \le 红线右边的所有元素的值,由于两个数组都是有序数组,在同一个数组内,分割线一定满足左边的所有元素小于等于右边元素。在不同的数组之间,应该保证交叉小于等于关系成立,如下图:

那么只要不符合小于等于关系,我们就需要适当调整分割线的位置。
(1)情况1

虽然这个是数组之和为奇数,左半部分数组的元素个数比右半部分数组的元素个数多1,但是第二个数组(1, 7, 8, 10, 17)分割线左边位置的最大值8>第一个数组(2, 4, 6, 15)分割线右边位置的最小值6就不符合红线左边的所有元素的值 ≤ \le 红线右边的所有元素的值,也就是说中位数右边的数太小了,调整方案:将中位数分割线在数组1的位置右移
(2)情况2:

第一个数组(2, 4, 6, 8, 10, 17)分割线左边位置的最大值8>第二个数组(1, 7, 15, 10)分割线右边位置的最小值7就不符合红线左边的所有元素的值 ≤ \le 红线右边的所有元素的值,也就是说中位数左边的数太大了,调整方案:将中位数分割线在数组1的位置左移

二分查找算法就是在这样尝试找到恰当的分割线的过程当中,不断地缩小搜索区间的范围,直到最终找到符合条件的分割线的位置,又由于我们需要比较分割线两侧元素的大小关系,在返回数组下标的时候,很有可能就出现下面两类极端的情况:
(1)较短的数组在分割线的右边没有元素和较短的数组在分割线的左边没有元素


由于我们需要通过访问“中间数分割线”左右两边的元素,因此应该在较短的数组上确定“中间数分割线”的位置。
(3)第二类情况发生在两个数组长度相等的时候
第一种,第一个数组在分割线的右边没有元素,并且第二个数组在分割线的左边没有元素

第二章,第二个数组在分割线的左边没有元素,并且第二个数组在分割线的右边没有元素


分割线的定义:
分割线在第一个数组右边的第1个元素的下标为i = 分割线在第一个数组左边的元素个数
分割线在第二个数组右边的第1个元素的下标为j = 分割线在第二个数组左边的元素个数

观察到,两数组长度和为奇数的时候,每个数组的分割线左侧的第一个元素的最大值即为中位数,两数组长度和为偶数的时候,每个数组的分割线左侧的第一个元素的最大值和右侧的第一个元素的最小值的均值即为中位数。

2. 代码实现

C语言实现该题,思路全在注释中:

//选出两个整数之间的最小值和最大值
int Min(int a, int b)
{if (a > b){return b;}else{return a;}
}
int Max(int a, int b)
{if (a < b){return b;}else{return a;}
}
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {//如果有空数组,则直接返回非空数组的中位数if(nums1 == NULL || nums1Size == 0){//奇数长度返回中间,偶数取中间两个均值if(nums2Size % 2 == 0){int mid = (nums2Size - 1) >> 1; //返回的是下标中点,不是数量中点return (double)((nums2[mid] + nums2[mid + 1]) / 2.0);}else{return nums2[nums2Size / 2];}}if(nums2 == NULL || nums2Size == 0){//奇数长度返回中间,偶数取中间两个均值if(nums1Size % 2 == 0){int mid = (nums1Size - 1) >> 1;return (double)((nums1[mid] + nums1[mid + 1]) / 2.0);}else{return nums1[nums1Size / 2];}}//如果第一个数组的长度大于第二个数组的长度,那就交换以下,让较短的数组成为第一个数组if(nums1Size > nums2Size){//交换数组指针int* temp = nums1;nums1 = nums2;nums2 = temp;//交换数组长度变量int tmp = nums1Size;nums1Size = nums2Size;nums2Size = tmp;}//数组1和数组2的长度分别用变量m和n表示int m = nums1Size;int n = nums2Size;//分割线左侧元素个数int totalLeft = (m + n + 1)>>1; //向右移动1位相当于除2//在nums1的区间[0, m]里查找恰当的分割线。//分割线在第一个数组左边的最大值nums1[i-1]要小于等于分割线在第二个数组右边的最小值nums2[j]//并且,分割线在第二个数组左边的最大值nums2[j-1]要小于等于分割线在第一个数组右边的最小值nums1[i]//这个就是我们分析出来的交叉的不等关系int left = 0;int right = m;//以长度最小的数组做循环变量的二分while(left < right){//分割线在第一个数组的下标//+1的原因://比如偶数长度的数组[1, 2, 3, 4]//开始的(left + right) / 2为1,其实我们的i应该是分割线右侧,即i为2,我们应该向上取整,向上取整就应该+1后再除2//奇数长度因为我们也要将i设置为中位数右侧第一个元素下标的值(对应上面文中的规则)int i = (left + right + 1) >> 1;//分割线在第二个数组的下标//比如两个数组[1, 2]和[3, 4, 5, 6]//i=0,则我们没有把第二个数组的开始和结束下标记作left和right//只能通过totalLeft间接推出//totalLeft=3,totalLeft是两个数组合并后的相对的左侧数组的元素个数//totalLeft-i相当于把左侧数组中第一个数组左侧的元素数减掉,只剩下第二个数组左侧的元素数//第二个数组左侧元素的个数恰好就是第二个数组的分割线的位置jint j = totalLeft - i;// 第一个数组中分割线左侧的元素大于第二个数组中分割线右侧的元素// 说明分割线在第一个数组上的位置太靠右了,所以分割线位置在i这个位置的左侧(不包括i)// 所以下一轮位置,所以下一轮搜索区间是[left, i - 1]if(nums1[i-1] > nums2[j]){right = i - 1;}//else// 如果恰好满足条件了,则将第一个数组右侧的元素和第二个数组左侧的元素算作两个新数组继续二分{left = i;}}//确定二分到最后的数组的分割线int i = left;int j = totalLeft - i;//求出第一个数组的分割线的左侧的最大值和右侧的最小值的变量//第二个数组以此类推//先初始化为0int nums1LeftMax = 0;int nums1RightMin = 0;int nums2LeftMax = 0;int nums2RightMin = 0;//如果最后的分割线i为0时,说明第一个数组分割线左侧数组的最大值不存在,则令此时的nums1LeftMax = INT_MIN//如果最后的分割线i为m时,说明第一个数组分割线右侧数组的最小值不存在,则令此时的nums1RightMin = INT_MAX//同理第二个数组j为0或者n时,以此类推if(i == 0){nums1LeftMax = INT_MIN;nums1RightMin = nums1[i];}else if(i == m){nums1LeftMax = nums1[i-1];nums1RightMin = INT_MAX;}else{nums1LeftMax = nums1[i-1];nums1RightMin = nums1[i];}if(j == 0){nums2LeftMax = INT_MIN;nums2RightMin = nums2[j];}else if(j == n){nums2LeftMax = nums2[j-1];nums2RightMin = INT_MAX;}else{nums2LeftMax = nums2[j-1];nums2RightMin = nums2[j];}//如果是奇数,返回的是分割线左侧的两个数组对应的元素的最大值//即分割线左侧要找到的是最大值//如果是偶数,返回的是分割线左侧的两个数组对应的元素的最大值和右侧的最小值的均值if((n+m)%2 == 1){return Max(nums1LeftMax, nums2LeftMax);}else{return (double)((Max(nums1LeftMax, nums2LeftMax) + Min(nums1RightMin, nums2RightMin)) / 2.0);}
}

最后也是顺利通过:

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

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

相关文章

【QT5】<总结> QT主要技术点

文章目录 前言 一、QT串口编程 二、QT网络编程 三、QT多线程 四、QT连接数据库 五、开发板上运行QT程序 前言 在学习QT的过程中&#xff0c;旨在更好地巩固所学到的知识&#xff0c;本篇总结QT在嵌入式开发中的主要技术点。 一、QT串口编程 思维导图&#xff1a; 知识点…

webrtc新版本无法连接peerconnection_server、无法音视频互通no incoming video...问题解决

问题1:无法连接peerconnection_server 在webrtc大概2022之后的版本,会出现无法连接peerconnection_server的现象,如下图: 在peerconnection_client界面点击Connect无法连接server. 解决办法 我们需要修改peerconnection_client的main.cc代码,如下图: 新添加的类代码…

Python第二语言(十一、Python面向对象(下))

目录 1. 封装 1.1 私有成员&#xff1a;__成员、__成员方法 2. 继承&#xff1a;单继承、多继承 2.1 继承的基础语法 2.2 复写 & 子类使用父类成员 3. 变量的类型注解&#xff1a;给变量标识变量类型 3.1 为什么需要类型注解 3.2 类型注解 3.3 类型注解的语法 3.…

LeetCode452用最少数量的箭引爆气球

题目描述 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处…

【C++进阶学习】第一弹——继承(上)——探索代码复用的乐趣

前言&#xff1a; 在前面&#xff0c;我们已经将C的初阶部分全部讲完了&#xff0c;包括类与对象、STL、栈和队列等众多内容&#xff0c;今天我们就进入C进阶部分的学习&#xff0c;今天先来学习第一弹——继承 目录 一、什么是继承&#xff1f;为什么会有继承&#xff1f; 二…

视频监控汇聚平台:系统日志介绍及在运维中的实际应用

目录 一、系统日志的重要性 &#xff08;一&#xff09;安全保障 &#xff08;二&#xff09;故障排查 &#xff08;三&#xff09;运营管理 &#xff08;四&#xff09;事件回溯与分析 二、产品说明 &#xff08;一&#xff09;产品介绍 &#xff08;二&#xff09;接…

前缀和算法:算法秘籍下的数据预言家

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一. 前缀和算法的介绍 二、前缀和例题 2.1 【模版】前缀和 2.2 【模板】二维前缀和 2.3 寻找数组的中间下标 2.4 除自身以外数组的乘积 2.5 和为k的子数组 2.6 和可被k整除的子数组 2.7 …

Spring 内置BeanFactoryPostProcessor的子孙们

同样的Spring 也 内置了 一些实现 BeanFactoryPostProcessor的类&#xff0c;各有各的用处。 spring-context AspectJWeavingEnabler 用来把ClassPreProcessorAgentAdapter注册到LoadTimeWeaver中ConfigurationClassPostProcessor 一个重要的类&#xff0c;用来处理Configurat…

基础-02-数据通信基础

文章目录 1.信道特征1.1 数据通信概念1.2 信道特性-信道带宽W1.3 信道特性-码元和码元速率1.4 信道特性-奈奎斯特定理1.5 信道特性-香农定理1.6 带宽/码元速率/数据速率关系梳理1.7 练习题 2.信道延迟2.1 信道延迟概念2.2 信道延迟计算2.3 练习题 3. 传输介质3.1 传输介质概念3…

家用洗地机什么牌子好?怎么选择高性价比洗地机

洗地机已成为现代家居清洁的好帮手&#xff0c;承担着家庭卫生的重要角色&#xff0c;随着日常清洁需求的提升&#xff0c;一台高效、便捷的洗地机成为众多家庭的追求。市场上的洗地机品牌众多&#xff0c;每个品牌下又有诸多系列&#xff0c;让人在选购时难免感到迷茫。又如何…

服务器哪些因素会影响到网站SEO优化?

您是否曾想过&#xff0c;您的 SEO 性能下降&#xff0c;可能是网站服务器出了问题?鉴于此&#xff0c;在本文中&#xff0c;我们将探讨哪些服务器因素会影响您网站的 SEO&#xff0c;并提供可行的建议。 页面速度 搜索引擎非常看重您网站的加载速度。加载缓慢的网站会给用户体…

【云原生】创建harbor私有仓库及使用aliyun个人仓库

1.安装docker #删除已有dockersystemctl stop docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine #安装docker yum install -y docker-ce-20.10.1…

SolarWinds Serv-U 目录遍历漏洞复现(CVE-2024-28995)

SolarWinds Serv-U 目录遍历漏洞复现(CVE-2024-28995) 1.漏洞描述 SolarWinds 是一家提供广泛的 IT 管理和网络管理软件解决方案的公司。SolarWinds 的产品被设计用于监控和管理网络设备、服务器、应用程序和网络流量等。Serv-U 是 SolarWinds 提供的一款 FTP&#xff08;文件…

Java 开发实例:Spring Boot+AOP+注解+Redis防重复提交(防抖)

文章目录 1. 环境准备2. 引入依赖3. 配置Redis4. 创建防重复提交注解5. 实现AOP切面6. 创建示例Controller7. 测试8. 进一步优化8.1 自定义异常处理8.2 提升Redis的健壮性 9. 总结 &#x1f389;欢迎来到Java学习路线专栏~探索Java中的静态变量与实例变量 ☆* o(≧▽≦)o *☆嗨…

12306 火车票价格解析 (PHP 解析)

1. 从接口拿数据 日期 出发站 终点站 都填上 xxx/otn/leftTicketPrice/queryAllPublicPrice?leftTicketDTO.train_date2024-06-15&leftTicketDTO.from_stationBJP&leftTicketDTO.to_stationSJP&purpose_codesADULT 返回的数据是这样的 {"validateMess…

3D工艺大师:航空航天手册的数字蜕变

在航空航天领域&#xff0c;技术手册是飞行器操作与维修工作的核心参考工具。常见的技术手册包括AMM&#xff08;航空器维护手册&#xff09;、CMM&#xff08;航空部件维修手册&#xff09;以及WDM&#xff08;飞机重量与平衡手册&#xff09;等&#xff0c;主要用于帮助机组工…

怎么批量去除EXCEL表格内时间?(已解决)

作为竞价优化师&#xff0c;经常碰到下载表格以后发现有冗余数据&#xff0c;这个时候我们该怎么快速处理呢&#xff01; 第一步&#xff0c;选择这一行数据 第二步&#xff0c;右击选择“单元格格式-日期” 第三步&#xff0c;选择日期中的2001-3-7格式&#xff0c;点击“确定…

向量化在人工智能领域的深度实践:技术革新与效率提升

在人工智能&#xff08;AI&#xff09;的飞速发展中&#xff0c;向量化技术作为一种基础且关键的数据处理手段&#xff0c;正日益受到广泛关注。向量化是将文本、图像、声音等数据转换为数值向量的过程&#xff0c;这些向量能够表示原始数据的特征和语义信息&#xff0c;为深度…

Ubuntu 22.04安装 docker

安装过程和指令 # 1.升级 apt sudo apt update # 2.安装docker sudo apt install docker.io docker-compose # 3.将当前用户加入 docker组 sudo usermod -aG docker ${USER} # 4. 重启 # 5. 查看镜像 docker ps -a 或者 docker images # 6. 下载镜像 docker pull hello-world …