4.寻找两个正序数组的中位数

embedded/2024/9/23 19:41:22/

杂谈:

        题目不难,最好想的当然是类似归并排序,也就是每次从nums1和nums2中拿一个更小的,直到某一个为空,或者找到了中间那个数(nums1.size()+nums2.size())/2

        这里主要记录一下官解给出的另外两种对数级的算法,主要是尝试用一个解题人的思想来理解算法

法一: 比较第k大,每次舍一半 O(log(m+n))

        我们取两个序列中第 k/2-1 大的元素,nums1的记为a,nums2的记为b,不妨设a<=b,又由于两个序列都是正序的,所以比a小的只可能是 nums1中0...k/2-2 和 nums2中0...k/2-2,这一共是 k/2-1 + k/2-1 <= k-2,也就是说a最大是第k-1大,也就说明a和它前面的那些元素都可以被舍弃.

        而当一个序列为空,直接返回另一个序列按序的指定元素即可, 因为我们每次舍弃k/2-1个,而当一个序列为空,就直接找到所求元素了,所以时间复杂度是O(log(m+n))

参考代码如下:

class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {//法一: 归并排序 O(m+n)//法二: 删除小者的那一半log(m+n)//法三: m<n 对[0,m-1]做一个二分查找int m=nums1.size(),n=nums2.size();int k=(m+n+1)/2;//// 0...k/2-2,k/2-1...m-1   0...k/2-2,k/2-1...n-1// 所以对于nums1[k/2-1]和nums2[k/2-1]的小者,记为a//   至多只有 nums1的0...k/2-2 和 nums2的0...k/2-2 共 k/2-1 + k/2-1 <= k-2 个数,// 所以a至多是第k-1小,而中位数(第k小,前面一共k-1个数)也不会被误删auto ans=findKth(nums1,nums2,k,0,0);return (m+n)%2?ans.first:(ans.first+ans.second)*1.0/2;}
//我们直接同时取到 第k大 和 第k+1大pair<int,int> findKth(vector<int>& nums1,vector<int>& nums2,int k,int index1,int index2){if(index1>=nums1.size()){//nums1为空if(index2+k<nums2.size()){return {nums2[index2+k-1],nums2[index2+k]};}else{return {nums2[index2+k-1],INT_MAX};}}if(index2>=nums2.size()){//nums2为空if(index1+k<nums1.size()){return {nums1[index1+k-1],nums1[index1+k]};}else{return {nums1[index1+k-1],INT_MAX};}}if(k==1){// 12都非空,但是k=1了int first=INT_MAX,second=INT_MAX;if(nums1[index1]<=nums2[index2]){first=nums1[index1];second=nums2[index2];if(index1+1<nums1.size()) second=min(second,nums1[index1+1]);}else{first=nums2[index2];second=nums1[index1];if(index2+1<nums2.size()) second=min(second,nums2[index2+1]);}return {first,second};}int k1=k/2-1;int tmp1=INT_MAX,tmp2=INT_MAX;int cut1,cut2;//cut1 和 cut2是删除的个数if(index1+k1<nums1.size()){tmp1=min(tmp1,nums1[index1+k1]);cut1=k/2;}else{cut1=nums1.size()-index1;}if(index2+k1<nums2.size()){tmp2=min(tmp2,nums2[index2+k1]);cut2=k/2;}else{cut2=nums2.size()-index2;}if(tmp1<=tmp2){//比较这次选中的 两个元素return findKth(nums1,nums2,k-cut1,index1+cut1,index2);}else{return findKth(nums1,nums2,k-cut2,index1,index2+cut2);}}
};

法二: 根据中位数的定义

        我们找一个i,把nums1分成两部分, nums1[0...i-1](i个) 和 nums[i...m-1](m-i个),我们找一个j,同样把nums2分成两部分,nums2[0...j-1](j个) 和 nums[j...n-1](n-j个),如果能够使得前面(i+j) 个 和后面(m-i+n-j)个满足中位数的定义,就是了

        如果m+n是偶数,我们就找 i+j=m-i + n-j 同时使得

                                                nums1[i-1]<=nums[j] && nums2[j-1]<=nums1[i]​​​​​​​

        如果m+n是奇数,我们就找 i+j=m-i + n-j +1 同时使得

                                                nums1[i-1]<=nums[j] && nums2[j-1]<=nums1[i]

统一一下就是 i+j = (n+m+1)/2

那也就是找 i,j 使得 i+j = (n+m+1)/2 同时 nums1[i-1]<=nums[j] && nums2[j-1]<=nums1[i]

​​​​​​​这个命题等价于 寻找最大的 i 使得满足 i+j = (n+m+1)/2 同时 nums1[i-1]<=nums2[j], 简单证一下:

        首先说明存在, 随着i增大 nums1[i-1]增大 nums2[j]下降,所以会存在一个最大的i满足上式

        既然是最大的i那就说明,对i+1上式不成立,  也就是说(i+1) + (j-1) = (n+m+1)/2 而nums1[i] > nums2[j-1],也就是nums2[j-1]<nums1[i],甚至比原命题更强

        同时对于边界,我们取nums1[-1]=nums2[-1]=INT_MIN,nums1[n]=nums2[m]=INT_MAX,这样保障即使边界也是能正确取值的

        参考代码如下:

class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {//法一: 归并排序 O(m+n)//法二: 删除小者的那一半log(m+n)//法三: m<n 对[0,m-1]做一个二分查找if(nums2.size()<nums1.size()){return findMedianSortedArrays(nums2,nums1);}//现在nums1是元素个数更少的了//0...i-1  |  i...m-1//0...j-1  |  j...n-1//i+j = n-i +m-j  ||  i+j = n-i +m-j+1 (或者左边多一个元素,所以是等于右边+1)  -> //我们要求出来最大的i, 使得nums1[i-1]<nums2[j],nums2[j-1]<nums1[i]int m=nums1.size(),n=nums2.size();int l=0,r=nums1.size();int median1=INT_MIN,median2=INT_MIN;while(l<=r){int mid=(r-l)/2+l;int i=mid;int j=(m+n+1)/2-i;int nums1_i1=i==0?INT_MIN:nums1[i-1];int nums1_i =i==m?INT_MAX:nums1[i];int nums2_j1=j==0?INT_MIN:nums2[j-1];int nums2_j =j==n?INT_MAX:nums2[j];if(nums1_i1<=nums2_j){median1=max(nums1_i1,nums2_j1);median2=min(nums1_i, nums2_j);l=mid+1;}else{r=mid-1;}}return (m+n)%2?median1:(median1+median2)/2.0;}
};


http://www.ppmy.cn/embedded/21564.html

相关文章

一款神奇的地理数据可视化python库

在地理信息系统&#xff08;GIS&#xff09;和地理数据可视化领域&#xff0c;Python的易用性和强大的库支持使其成为处理地理数据的理想选择之一。今天我们介绍Cartopy库&#xff0c;它为地理数据可视化提供了强大的支持。无论是对于GIS专业人士还是对地理数据可视化感兴趣的初…

四、通信和网络安全—网络通信基础与网络基础设施(CISSP)

目录 一、网络通信基础 1.网络通信类型 2.网络拓扑结构 2.1 网络拓扑技术比较

ubuntu16.04配置rsh

Ubuntu16.04 配置rsh服务&#xff1a; 1&#xff1a;先安装以下软件&#xff1a; sudo apt-get rsh-server sudo apt-get rsh-client sudo apt-get rsh-redone-server sudo apt-get xinetd 2&#xff1a;在/etc/hosts 中添加访问的主机ip和主机名 192.168.0.66 cpci6200…

同事上班这样摸鱼,我坐边上咋看他都在专心写代码啊

我边上有个同事&#xff0c;我坐他边上&#xff0c;但是每天看着他都眉头紧锁&#xff0c;忙的不亦乐乎&#xff0c;但终于有一天&#xff0c;我发现了他上班摸鱼的秘诀。 我劝你千万不要学会这4招&#xff0c;要不就该不好好上班了。 目录 1 上班看电影&#xff1f; 2 上班…

异常漩涡:深入了解 Java 异常传播与处理链

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一个人虽可以走的更快&#xff0c;但一群人可以走的更远。 我是一名后…

blender Principled Hair BSDF

三种模式&#xff1a; Direct Coloring 直接指定所需的RGB颜色值着色器会尝试近似所需的吸收系数来模拟该颜色Melanin Concentration 使用更加物理化的方式定义头发/毛发颜色通过指定黑色素(Melanin)的浓度和黑红色素(Pheomelanin/Eumelanin)的比例来确定颜色更符合头发/毛发中…

lua中的pcall和xpcall和直接调用一个函数的区别

1、pcall 在 Lua 中&#xff0c;pcall 函数用于以一种安全的方式调用另一个函数&#xff0c;并捕获任何可能发生的错误。而直接调用一个函数则是简单地执行该函数的代码。下面是它们之间的区别&#xff1a; 错误处理&#xff1a; 直接调用函数&#xff1a;如果在直接调用一个函…

深度合作推动行业进步:百数低代码平台与昌宜同方租赁领域的合作案例分享

随着信息化的飞速发展&#xff0c;业务管理逐渐成为企业核心竞争力的关键要素之一。特别是对于租赁业务的公司&#xff0c;能够实时跟进项目及到款情况&#xff0c;对于提高工作效率和客户满意度至关重要。昌宜同方&#xff08;武汉&#xff09;新型建材科技有限公司&#xff0…