【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.mzph.cn/diannao/27378.shtml

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

相关文章

消息队列的应用场景有哪些

通常来说&#xff0c;使用消息队列主要能为我们的系统带来下面三点好处&#xff1a; 异步处理 削峰/限流 降低系统耦合性 除了这三点之外&#xff0c;消息队列还有其他的一些应用场景&#xff0c;例如实现分布式事务、顺序保证和数据流处理。 异步处理 通过异步处理提高系…

计算机网络:网络层 - IPv4数据报 ICMP协议

计算机网络&#xff1a;网络层 - IPv4数据报 & ICMP协议 IPv4数据报[版本 : 首部长度 : 区分服务 : 总长度][标识 : 标志 : 片偏移][生存时间 : 协议 : 首部检验和][可变部分 : 填充字段] ICMP协议 IPv4数据报 一个IPv4数据报&#xff0c;由首部和数据两部分组成&#xff…

Python 越来越火爆

Python 越来越火爆 Python 在诞生之初&#xff0c;因为其功能不好&#xff0c;运转功率低&#xff0c;不支持多核&#xff0c;根本没有并发性可言&#xff0c;在计算功能不那么好的年代&#xff0c;一直没有火爆起来&#xff0c;甚至很多人根本不知道有这门语言。 随着时代的…

递归解析 LXML 树并避免重复进入某个节点

1、问题背景 我们在使用 LXML 库解析 MathML 表达式时&#xff0c;可能会遇到这样一个问题&#xff1a;在递归解析过程中&#xff0c;我们可能会重复进入同一个节点&#xff0c;导致解析结果不正确。例如&#xff0c;我们希望将以下 MathML 表达式解析为 Python 表达式&#x…

【数据结构初阶】--- 栈和队列

栈 栈的定义 栈&#xff1a;只允许在一端进行插入或删除的操作 事实上&#xff0c;线性表和链表都可以实现栈&#xff0c;但栈的特点更符合用顺序表实现 顺序表的队尾相当于栈顶&#xff0c;对栈放入数据&#xff0c;相当于顺序表的下标arr[index] x&#xff0c;而栈弹出数…

什么是无头浏览器以及其工作原理?

如果您对这个概念还不熟悉&#xff0c;那么使用无头网络浏览器的想法可能会让您感到不知所措。无头浏览器本质上与您熟悉的网络浏览器相同&#xff0c;但有一个关键区别&#xff1a;它们没有图形用户界面 (GUI)。这意味着没有按钮、选项卡、地址栏或视觉显示。 相反&#xff0c…

硬盘几个关键指标你一定要知道!

硬盘是数据中心中存储数据的重要部件&#xff0c;其关键指标影响硬盘的性能、可靠性和适用性。以下是一些常见的硬盘关键指标&#xff0c;并附上详细解释和举例&#xff1a; 容量&#xff08;Capacity&#xff09; 解释&#xff1a;硬盘的容量指其能存储数据的总量&#xff0c;…

CPN Tools学习——时间和队列【重要】

-Timed Color Sets 时间颜色集 -Token Stamps 令牌时间戳 -Event Clock 全局/事件/模拟时钟 -Time Delays on Transitions过渡的时间延迟 - List Color Set列表颜色集 - Queue排队 1.时间颜色集 在定时CPN模型令牌中有&#xff1a; &#xff08;1&#xff09;象征性的颜…

银河麒麟系统项目部署

使用服务器信息 软件&#xff1a;VMware Workstation Pro 虚拟机&#xff1a;ubtun 内存&#xff1a;20G 虚拟机连接工具&#xff1a; MobaXterm Redis连接工具&#xff1a; RedisDesktopManager 镜像&#xff1a;F:\Kylin-Server-10-8.2-Release-Build09-20211104-X86_64…

js: 百度云BOS 分片上传

百度云BOS存储后怎么查看或下载呢&#xff1f; // 1) 查看登录到百度智能云控制台 – 对象存储BOS”服务–选择一个Bucket&#xff0c;进入后可以查看该Bucket下的所有文件和文件夹。 2&#xff09;下载OS浏览器端不支持批量下载&#xff0c;可以通过以下方式下载文件(使用BOS桌…

WindTerm使用SSH密钥连接阿里云实例,服务器设置SSH密钥登录

安装Windterm 地址https://github.com/kingToolbox/WindTerm/releases 下载完放到文件夹就可以打开 阿里云开启密钥对 打开阿里云ecs控制台 https://ecs.console.aliyun.com/keyPair/region/cn-wulanchabu 网络与安全->密钥对&#xff0c;创建密钥对&#xff0c;创建成…

记一次 .NET某工控视觉自动化系统 卡死分析

一&#xff1a;背景 1. 讲故事 今天分享的dump是训练营里一位学员的&#xff0c;从一个啥也不会到现在分析的有模有样&#xff0c;真的是看他成长起来的&#xff0c;调试技术学会了就是真真实实自己的&#xff0c;话不多说&#xff0c;上windbg说话。 二&#xff1a;WinDbg …

hbase安装部署

1&#xff0c;下载依赖包 最近的版本下载镜像 https://mirrors.aliyun.com/apache/hbase/ 比较旧的版本下载 https://archive.apache.org/dist/hbase 2&#xff0c;解压压缩包 3&#xff0c;更改配置 3-1 修改hbase-env.sh 必须加 JAVA_HOME export JAVA_HOME/usr/jdk64/jdk…

前端技术回顾系列 11|TS 中一些实用概念

在微信中阅读,关注公众号:CodeFit。 创作不易,如果你觉得这篇文章对您有帮助,请不要忘了 点赞、分享 和 关注 我的公众号:CodeFit,为我的持续创作提供动力。 上文回顾:泛型在类和接口中的应用 上一篇文章我们回顾了 泛型 在 类 和 接口 中的应用。 通过使用泛型,我们…

动态规划-简单多状态dp问题 -- 按摩师

动态规划-简单多状态dp问题 – 按摩师 文章目录 动态规划-简单多状态dp问题 -- 按摩师题目重现算法流程示例代码 题目重现 题目链接&#xff1a;按摩师 - 力扣 一个有名的按摩师会收到源源不断的预约请求&#xff0c;每个预约都可以选择接或不接。在每次预约服务之间要有休息时…

IINA for Mac v1.3.5 音视频软件 安装教程(保姆级)

Mac分享吧 文章目录 效果一、准备工作二、开始安装1、双击运行软件&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功 三、运行测试1、打开软件&#xff0c;测试2、查看版本号 **安装完成&#xff01;&#xf…

C#——结构体详情

结构体 结构体也被称为结构类型&#xff08;“structure type”或“struct type”&#xff09;&#xff0c;它是一种可封装数据和相关功能的值类型&#xff0c;在语法上结构体与类&#xff08;class&#xff09;非常相似&#xff0c;它们都可以用来封装数据&#xff0c;并且都…

【C语言】递归复杂度与链表OJ之双指针

【C语言】递归复杂度与链表OJ之双指针 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;数据结构 文章目录 【C语言】递归复杂度与链表OJ之双指针前言一.递归复杂度1.1递归时间复杂度1.2递归空间复杂度 二.链表OJ之双指针2.1倒数第K个节点2.2链…

FastJson与JackSon 的碰撞。服务发送方与服务接收方字段不一致问题

情景再现 对接文档人家要求字段为 于是乎 咱就在服务的发送方定义参数字段为 服务接收方接收的类型为 later。。。。。 服务接收方接收到的参数字段 就不变成了fOrgId。跟外部系统对接就提示参数错误 原因 &#xff1a;lombok 在做set get的时候自动 无论你字段的首字母是大…

我与Python的一夜情

期末突击看这篇才够味&#xff01; 环境搭建 首先就是相关工具的安装&#xff0c;直接搜就好&#xff0c;但是还是贴个网址吧&#xff1a; Welcome to Python.orghttps://www.python.org/ 然后就是根据自己的系统选择咯&#xff1a; 谁能闲来无事送我个mac玩玩 Windows的一…