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

思路一(暴力):

  当看到这个题目的时候可能会觉的是不是系统高估了这个题目,这个这么简单,只需要将两个数组合并,排序然后合并就好了。这样做确实可以求出中位数,但是并不能说是完成题目的要求,因为题目的要求时间复杂度是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…

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

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

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

来源&#xff1a;OFweek 摘要&#xff1a;智能家居已经火了有一段时间&#xff0c;然而目前真正普及的家庭并不多。从长远来看&#xff0c;智能家居是一种更环保、智能、舒适、安全的人居环境&#xff0c;它涉及物联网、人工智能等相关技术&#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位获奖者对数学领域…

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

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

传输层(学习笔记)

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

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…

一条光纤的传输容量高达 661Tbps(附论文)

来源&#xff1a;云头条摘要&#xff1a;研究人员将全世界目前的光纤容量塞入到一条链路中。社会对数据的渴求永无止境。事实上&#xff0c;想想这个就令人相当惊讶&#xff1a;平均的互联网流量是每秒几百兆兆位&#xff0c;耗电量约占我们发电量的8%。这一切用来传输猫咪即时…

tcp四次挥手,为什么是四次?

上一篇博客说了三次握手为什么是是三次&#xff08;点这里&#xff09;&#xff0c;那么现在就介绍一下四次挥手。大家都知道TCP是全双工的&#xff0c;再建立连接时的三次握手中的SYN和ACK一起发送&#xff0c;这里就会有疑问&#xff0c;为什么在四次挥手的时候没有将SYN和AC…

市值破万亿美金的苹果 近年在AI上搞了些新动作

来源&#xff1a;网易智能2007年&#xff0c;中石油在中国A股市场上市首日市值曾达到1.1万亿美元。11年之后&#xff0c;当地时间8月2日&#xff0c;苹果公司盘中市值也超过1万亿美金&#xff0c;成为继中石油后的第二家破万亿公司。苹果股价以207.39美元收盘&#xff0c;涨幅为…

网络层(学习笔记)

网络层 负责地址管理与路由选择&#xff0c;在复杂的通信环境中 IP协议 IP协议头格式 4位协议版本&#xff1a;IPV4/IPV6 4位头部长度&#xff1a;表示ip头有多长&#xff0c;最长60字节&#xff0c;最小20字节 8位服务类型&#xff1a;TOS字段&#xff08;最小延时&#xff…

jQuery 的各种练习

这个星期最大的感悟是&#xff0c;只有在实践中不断的总结&#xff0c;才能打下扎实基本功。这是本周主要做的东西&#xff1a; 第一个图主要为对jQuery ajax的练习。后面两个计算器和新浪微博页面为之前做好的页面&#xff0c;这次用一个load()函数把它们加载进来。不过中间的…

蜜糖变砒霜:90%美国公司区块链项目将不再重启

来源&#xff1a;雷锋网摘要&#xff1a;市场对区块链的“迷恋”来得轰轰烈烈&#xff0c;退得悄无声息。一方面是科技巨头占山为王&#xff0c;另一方面不少此前号称投入研发区块链的公司已经把目光收回&#xff0c;并且表示再也不会重启这些试点项目。有人觉得区块链就此沉寂…

【埋点】是什么埋点?简述埋点的操作流程

埋点&#xff1a;又称为事件追踪&#xff08;Event Tracking&#xff09;&#xff0c;指的是针对特定用户行为或事件进行捕获&#xff0c;处理和发送的相关技术及其实施过程。 功能方面&#xff1a;埋点是用来收集用户行为数据。比如想要了解一个用户在APP里面点击了哪些按钮&…