寻找两个有序数组的中位数(虚拟数组图文详解)

思路一(暴力):

  当看到这个题目的时候可能会觉的是不是系统高估了这个题目,这个这么简单,只需要将两个数组合并,排序然后合并就好了。这样做确实可以求出中位数,但是并不能说是完成题目的要求,因为题目的要求时间复杂度是O(log(m + n)),这个暴力算法的时间复杂度很明显是O(m+n),可以有兴趣的可以测一下,这个算法不是本博客的重点,这里不多赘述,代码如下:

    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {double ret = -1;vector<double> buff;//合并两个数组for (auto e : nums1)buff.push_back(e);for (auto a : nums2)buff.push_back(a);//将合并后的结果进行排序sort(buff.begin(), buff.end());int size3 = buff.size();//获取中位数if (size3 % 2 == 0){ret = ((buff[size3 / 2] + buff[size3 / 2 - 1]) / 2);}elseret = buff[size3 / 2];return ret;
}
思路二:分治+二分查找
题目解析:

  这个题目简单来说就是如果将两个已经排序的数组合并为一个虚拟数组,求出这个虚拟数组的中位数即可。

解题思路:

  1、这道题最主要的就是切(cut),怎么将数组切成合适的两段是关键,对于一个数组来说在数组的中间将其切成两段,这时候就要分情况讨论,如果是偶数个,中位数就是切点的两边第一个数的平均值,如果是奇数个,中位数就是切点右边的第一个数,比如说1 2 3 4 5,在中间的位置将这个数组切成两段:1 2 \ 3 4 5,很显然,中位数就是3,如果是1 2 3 4,那么就切成了1 2 \ 3 4,很显然中位数就是(2+3)/2 = 2.5。
  2、理解了切的思想,接下来就开始在两个数组中进行切,这时候就用到了分治思想。
  怎么分?
  题目中要求的时间复杂度为 O(log(m + n)),很容易想到的方法就是二分,现在有两个数组,要对那个数组进行二分合适?由于找的是中位数,那么这个数字的两边的元素个数是相等的,所以只需要确定一个数组中的两边元素,两一个数组的对应的补上去就可以了,为了提高效率,要选择最短的数组做二分查找。
  怎么治?
  这个也很容易,只需要分别比较两个数组切点两边的数就可以,假设数组1中切点两边的元素为L1,R1,数组2中切点两边的元素为:L2,R2,切完之后有三种情况:
  1)L1>R2 ,说明数组1的左半边比数组2的右半边大,应该让cut向左移,才能使数组一中较多的数被分配到右边。
  2)L2>R1 ,说明数组2的左半边比数组1的右半边大,应该让cut向右移,才能使数组一中较多的数被分配到左边。
  3)其他情况(L1<=R2 L2<=R1),cut的位置是正确的,可以停止查找,输出结果。
3.特殊情况
分析完了正常的情况,那么就要分析一下特殊情况;
  1)如果有一个数组是空的,直接返回另一个不为空的数组中的中位数
  2)如果两个数组元素的个数相等,并且两个数组的中位数相等,直接返回其中一个中位数。
  3)有可能在进行二分查找的时候出现了数组越界的情况,只需要定义一个最大值和一个最小值,这样可以按照正常的情况来处理了。
4、输出结果分情况
  两个数组的输出情况和之前的一个数组的输出大致是一样,只是添加了选择性,如果是偶数个,输出(min(L1, L2) + min(R1, R2))/2,如果是奇数个,输出min(R1, R2)。

图解思路:

在这里插入图片描述
  这里只对不越界和不为空的数组进行解析。
在这里插入图片描述

代码解析:
class Solution {
public:double MedNum(vector<int>& num){double ret;size_t size = num.size();if(size == 1)return num[0];int med = size / 2;if (size% 2 == 0){ret =  ((double)(num[med] + num[med - 1]) / 2);}elseret = num[med];return ret;}double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2){double ret = -1;//定义最小数和最大数const int BDL_MIN_ = 0x80000000;const int BDL_MAX_ = 0x7fffffff;//情况一://如果这两个数组中有一个是空的,直接返回另一个的中位数即可if (nums1.empty())return MedNum(nums2);else if (nums2.empty())return MedNum(nums1);//情况二://如果两个数组分别的中位数相等,那么这两个数的中位数就是这个中位数int size1 = nums1.size();	//数组一的长度int size2 = nums2.size();	//数组二的长度if(size1 == size2){Med1 = MedNum(nums1);Med1 = MedNum(nums1);if(Med1 == Med2)return Med1;}//情况三://使用分治思想,二分查找方法int size0 = size1 + size2;	//两个数组的总长度//为了效率,要选择最短的数组做二分查找,使数组一为最短//如果第一个数组比第二个数组长,就要使两个数组交换//但是swap的时间复杂度使O(N+M),所以将两个数组交换位置再调一次函数即可if (size1 > size2)return findMedianSortedArrays(nums2, nums1);//设置二分查找的范围int cutL = 0;int cutR = size1;//这里将cut1初始为数组1的中位数int cut1 = (size1 - 1) / 2;while (cut1 <= size1){cut1 = (cutR - cutL) / 2+cutL;                           //在数组1中找cut1切点(二分)int cut2 = (size0 / 2) - cut1;                           //在数组2中找cut2切点//这里不用size2直接确定切点,是因为将两个数组进行了虚拟合并,使用虚拟数组的总数size0找中间点,然后将属于数组一的部分减去,就是cut2在数组2中的切点,可以结合上面的图片捋一下。//确定L1,L2,L3,L4的值,并判断当前的切点有没有越界          double L1 = (cut1 == 0) ? BDL_MIN_ : nums1[cut1-1];double R1 = (cut1 == size1) ? BDL_MAX_ : nums1[cut1];double L2 = (cut2 == 0) ? BDL_MIN_ : nums2[cut2-1];double R2 = (cut2 == size2) ? BDL_MAX_ : nums2[cut2];//如果L1>R2,则cut1应该向左移,才能使数组1较多的数被分配到右边。if (L1 > R2)cutR = cut1-1;//如果L2 > R1,则cut1应该向右移,才能使数组1较多的数被分配到左边。else if (L2 > R1)cutL = cut1+1;//其他情况就是L1<=R2 L2<=R1,说明当前cut1和cut2的位置就是中位数的位置了else{//如果两个数组中加起来的元素数量是偶数,那么中位数就应该是两个中位数的平均值if (size0 % 2 == 0){L1 = max(L1, L2);R1 = min(R1, R2);ret = (L1 + R1) / 2;return ret;}//如果两个数组中元素的数量是奇数,中位数就是当前位置的右值else{ret = min(R1, R2);return ret;}}}return ret;}
};

如果有什么问题可以在评论区留言!

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

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

相关文章

uva540

题目的意思大概就是现在让你做一个数据结构&#xff0c;具体的应该是一个队列&#xff0c;有一堆元素&#xff0c;这堆元素拥有两个特性&#xff0c;一是它的值&#xff0c;二是它所在的team值。这个队列满足以下的一些性质&#xff08;操作&#xff09;。 ENQUEUE(k) &#xf…

Python面试题大全(五):测试、大数据、数据结构、架构

目录 测试 213.编写测试计划的目的是 214.对关键词触发模块进行测试 215.其他常用笔试题目网址汇总 216.测试人员在软件开发过程中的任务是什么 217.一条软件Bug记录都包含了哪些内容&#xff1f; 218.简述黑盒测试和白盒测试的优缺点 219.请列出你所知道的软件测试种类…

【决策】Waymo无人出租车年底发射,现已进入定价环节 | 公交部门竟成友军?...

开车栗 发自 凹非寺量子位 出品 | 公众号 QbitAI按照Waymo的计划&#xff0c;今年年底之前&#xff0c;他们的无人出租车服务就要进入市场了。现在&#xff0c;无人的士已进入了定价环节&#xff0c;紧张刺激。Waymo希望从此开始&#xff0c;人类能一点一点抛弃私家车&#xff…

盘点那些具有“爆款”潜力的智能家居产品

来源&#xff1a;OFweek 摘要&#xff1a;智能家居已经火了有一段时间&#xff0c;然而目前真正普及的家庭并不多。从长远来看&#xff0c;智能家居是一种更环保、智能、舒适、安全的人居环境&#xff0c;它涉及物联网、人工智能等相关技术&#xff0c;是人们理想的一种生活方式…

圆圈中最后剩下的数字

题目&#xff1a;n个数字&#xff08;0,1,…,n-1&#xff09;形成一个圆圈&#xff0c;从数字0开始&#xff0c;每次从这个圆圈中删除第m个数字&#xff08;第一个为当前数字本身&#xff0c;第二个为当前数字的下一个数字&#xff09;。当一个数字删除后&#xff0c;从被删除数…

TCP/IP校验和(浅析+实例)

校验和的作用   按照协议的规定&#xff0c;报文到达每一层&#xff0c;首先验证校验和是否正确&#xff0c;丢弃掉不正确的报文&#xff0c;再才会进行后续操作。  那么校验和是怎么计算的呢&#xff1f;  校验和的计算方法(以 IP 首部中的校验和为例) 方法是计算16位的二…

4位数学家获得2018年菲尔兹奖

来源&#xff1a;科学网2018年菲尔兹奖8月1日在巴西里约热内卢市举行的第28届国际数学家大会上揭晓&#xff0c;获奖者为伊朗裔数学家Caucher Birkar、意大利数学家Alessio Figalli、德国数学家Peter Scholze&#xff0c;以及印澳裔数学家Akshay Venkatesh。4位获奖者对数学领域…

ASP.NET GridView控件在列上格式化时间

症状&#xff1a;在GridView绑定日期格式的时候&#xff0c;数据库中的日期为2008-07-04&#xff0c;而GridView显示的是2007-07-04 000000。、 解决办法&#xff1a;想把这后面这多余的零去掉的话在绑定时间的那一列源码后面加上一句话就可以了&#xff0c;如下红色的部分 <…

spark-submit 参数设置

在使用spark时&#xff0c;根据集群资源情况和任务数据量等&#xff0c;合理设置参数&#xff0c;包括但不限于以下&#xff1a; 参数说明masteryarn E-MapReduce 使用 Yarn 的模式yarn-client&#xff1a;等同于 –-master yarn —deploy-mode client&#xff0c; 此时不需要…

科学研究发现,盲人用时间感知空间

来源&#xff1a;中国科学报摘要&#xff1a;在书籍和电影中&#xff0c;盲人通常用超敏感的听力帮助他们在现实世界中穿梭。在书籍和电影中&#xff0c;盲人通常用超敏感的听力帮助他们在现实世界中穿梭。但是&#xff0c;8月1日发表在iScience杂志上的一项研究表明&#xff0…

SharePoint创建web application的时候报错

今天在SharePoint Server上创建一个web application的时候报错了。 The password supplied with the username ***\*** was not correct. Verify that it was entered correctly and try again. 我之前是改过administrator的密码,但确实用stsadm.exe -o updatefarmcredentials…

传输层(学习笔记)

传输层基本概念&#xff1a; 传输层负责端与端之间的数据传&#xff0c;主要有两大知识点&#xff1a;TCP和UDP 五元组 在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过netstat -n查看); 端口号范…

随机读写 vs 顺序读写

磁盘是如何存储数据的&#xff1f; 信息存储在硬盘里&#xff0c;把它拆开也看不见里面有任何东西&#xff0c;只有些盘片。假设&#xff0c;你用显微镜把盘片放大&#xff0c;会看见盘片表面凹凸不平&#xff0c;凸起的地方被磁化&#xff0c;凹的地方是没有被磁化&#xff1b…

C# 析构函数(Destructor)和终结器(Finalizer)——托管资源的释放

本文内容 使用析构函数释放资源 Object.Finalize 方法 资源的显式释放 使用析构函数释放资源 析构函数用于析构类的实例。 不能在结构中定义析构函数。只能对类使用析构函数。 一个类只能有一个析构函数。 无法继承或重载析构函数。 无法调用析构函数。它们是被自动调用的。 析…

教育部:建设100+AI特色专业, 500万AI人才缺口要补上!

来源&#xff1a;网络大数据摘要&#xff1a;为落实《国务院关于印发新一代人工智能发展规划的通知》&#xff0c;为我国新一代人工智能发展提供战略支撑&#xff0c;教育部在近日正式发布了《高等学校人工智能创新行动计划》。AI再次被提上国家级日程!为落实《国务院关于印发新…

TCP三次握手详解及面试题

为什么必须是三次握手&#xff1f; 大家都知道传输层&#xff08;点击这里去传输层&#xff09;中的TCP协议是面向连接的&#xff0c;提供可靠的连接服务&#xff0c;其中最出名的就是三次握手和四次挥手&#xff0c;今天先讲解三次握手&#xff08;四次挥手点这里&#xff09;…

git 撤销修改:未push 、已push

场景&#xff1a;不小心把一次错误的代码push到远程服务器上的分支上&#xff0c;需要立即删除/撤销这次代码提交。 具体方法&#xff0c;git命令&#xff1a; git loggit reset --hard <commit_id>git push origin HEAD --force【命令详解】 获取commit_id&#xff1…

跳过堡垒机,一键登陆

使用场景&#xff1a; 在登陆公司堡垒机时&#xff0c;一般需要个人密码动态密码&#xff08;常为OTP密码&#xff09;&#xff0c;本文通过自动生成OTP密码实现一键登录。 如果是静态密码&#xff0c;跳过第一步&#xff0c;第二步去掉动态密码部分 第一步&#xff1a;获取…