我们首先来看一下这一类题算法的原型:

对应牛客网链接:

https://www.nowcoder.com/practice/08588d568e164e0a9958b5d6a3c351f5?tpId=101&&tqId=33149&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D101%26type%3D101%26page%3D2

题目描述:

给定两个有序数组arr1和arr2,已知两个数组的长度都为N,求两个数组中所有数的上中位数。

上中位数:假设递增序列长度为n,若n为奇数,则上中位数为第n/2+1个数;否则为第n个数

[要求]

时间复杂度为O(logN),额外空间复杂度为O(1)

第一行一个整数N,表示数组大小。
接下来一行N个整数,表示arr1内的元素
再接下来一行N个整数,表示arr内的元素

输出一个整数表示答案

输入:

4
1 2 3 4
3 4 5 6

复制输出:

3

复制说明:

总共有8个数,上中位数是第4小的数,所以返回3。

输入:

3
0 1 2
3 4 5

复制输出:

2

复制说明:

总共有6个数,那么上中位数是第3小的数,所以返回2

解题思路:

我首先在长度为偶数的数组中两个数组中求上中位数。我们首先求A数组中的上中位数为b

在B数组中求其上中位数位b我们比较b和b'的大小如如下三种情况:

1.如果b==b'那么b的值就是上中位数这是为什么了呢?我们将b和b'看作一个整体就可以了明白了.

2.如果b大于b'.对于A和B数组合并之后的上中位数那么它一定是第四小的数此时我们可以排除掉一些不可能是上中位数的数字比如说A数组中的c和d这是因为c和d本来就大于a,b而b有大于b'当然也大于a‘所以c和d不肯能是第四小的数。同理也可以排除b数组中的a'和b’.那么数组中就只剩下A数组中的a b和B数组中的c'和d'我们发现我们只要重复上面的过成就可以找到到上中位数。

3.b小于b‘与情况二相反同理可证,各位老铁可以自己下去证明即可

数组长度为奇数时:

在长度为奇数的数组中我们同样按照上面的操作先取出数组A和数组B的上中位数。A数组中的中位数为c 而B数组中的中位数为c'同样的有三种情况:

1.c==c‘那么c一定是上中位数

2.c大于c'时我们可以排除A数组中的c,d,e是不可能为第五小的数应为c大于a,b,a',b',c'不可能是第六小的数,而B数组中数组中a'和b'不可能是第五小的数。在这里我们发现不等长了A数组中有两个数而B数组中有两个数,解决方案我们只要手动验证c'看它和b的大小关系,如果是则返回如果不是则将其排除此时就变成等长的数组,我们就可以继续调算法原型

3.c<c'和2是同理的

总结:

首先分别找出两个数组arr1和arr2的中位数,分别为mid1,mid2,比较,如果mid1 == mid2,则该数即为所有数的上中位数。
       (1)mid1 > mid2时:
     若数组长度N为偶数时:因为mid1>mid2,所以mid2不可能是所有数的上中位数,arr1中mid1后面的数也不可能是上中位数,  此时两个数组就分别筛选掉了一半,然后递归对arr1的前半部分和arr2的后半部分求所有数的上中位数。
         若数组长度N为奇数时: 因为mid1>mid2,所以mid1不可能是所有数的上中位数,但mid2有可能是,由于球上中位数的两个数组
        必须等长,因此,我们递归对arr1的前半部分(包括mid1)和arr2的后半部分(包括mid2)求所有数的上中位数。
    ( 2) mid1 < mid2时的情况和 2)类似。

对应代码:

#include<iostream>
#include<vector>
using namespace std;
int GetMidNum(vector<int>&nums1,vector<int>&nums2){int start1=0;int start2=0;int end1=nums1.size()-1;int end2=nums2.size()-1;int mid1=0;int mid2=0;int offset=0;while(start1<end1){mid1=(end1+start1)/2;mid2=(end2+start2)/2;offset=((end1-start1+1)&1)^1;//判断数组的长度是偶数还是奇数if(nums1[mid1]>nums2[mid2]){end1=mid1;//变换下标start2=mid2+offset;}else if(nums1[mid1]<nums2[mid2]){start1=mid1+offset;end2=mid2;}else{return nums1[mid1];}}return min(nums1[start1],nums2[start2]);//返回最小的那一个
}
int main(){int n;cin>>n;vector<int>arr1(n);vector<int>arr2(n);for(int i=0;i<n;i++){cin>>arr1[i];}for(int i=0;i<n;i++){cin>>arr2[i];}cout<<GetMidNum(arr1,arr2);return 0;
}

下面我们在来看一个加强版的:

对应牛客网链接:

https://www.nowcoder.com/practice/b933e6a7924c44388fc08e807945f6c7?tpId=101&&tqId=33150&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D101%26type%3D101%26page%3D1

题目描述:

给定两个有序数组arr1和arr2,再给定一个整数K,返回所有数中第K小的数。

[要求]

如果arr1的长度为N,arr2的长度为M,时间复杂度请达到O(\log(\min{N, M}))O(log(minN,M)),额外空间复杂度O(1)O(1)。

第一行三个整数N, M, K分别表示数组arr1, arr2的大小,以及需要询问的数
接下来一行N个整数,表示arr1内的元素
再接下来一行M个整数,表示arr2内的元素

输出一个整数表示答案

输入:

5 3 1
1 2 3 4 5
3 4 5

复制输出:

1

复制说明:

1是所有数中第一小的数

输入:

3 4 4
1 2 3
3 4 5 6

复制输出:

3

复制说明:

3是所有数中第4小的数,所以返回3

解题思路:

1.当两个数组等长时我们可以调用上面的那一题的算法原型即可

2.当两个数组不等长时又分为两种情况

2.1 当k大于两个数组中长的那一个数组的长度时

假设我们要求第23小的数我们首先就可以排除1‘到到12’都是不可能的这是因为就算法他们都比A数组中的元素大也不可能是第23小的数

同理A中的1 2 3 4 5也是不可能的此时A数组中可能的元素和B中可能的元素的个数相同,那我们是不是可以调前面那个算法原型呢?假设可以我们在这10个数里面找到上中位数也就是这十个数里面第5小的数,我们可以计算一下前面比这个上中位数小的一共是17+4=21,此时并不是23小。

我们在这里需要将13‘和10做比较,将6和17做比较看他们两是不是上中位数。如果是则直接返回,如果不是我们此时只需要在剩下的8个数中找到第4小的数,这样计算一下发现刚好是第23小的数

2.2 k小于长数组的长度但是小于短数组的长度

假设我们要求第15小的数和上面同样的我们现在A数组中看那些数不可能首先A数组中所有的数都有可能

B数组中1’到4‘和16’到17‘是不可能是第十五小的数

我们发现B数组中可能的数有5’到15‘一共11个数而A数组中只有10个数长度不相等,此时我们手动验一下5’看它是否大于10如果大于则是第15小的数如果不是则将其排除就刚10个数和A数组等长,调用算法原型即可

对应代码:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
//算法原型int GetMidNum(vector<int>&nums1,int start1,int end1,vector<int>&nums2,int start2,int end2){int mid1=0;int mid2=0;int offset=0;while(start1<end1){mid1=(end1+start1)/2;mid2=(end2+start2)/2;offset=((end1-start1+1)&1)^1;//判断长度是奇数还是偶数if(nums1[mid1]>nums2[mid2]){end1=mid1;start2=mid2+offset;}else if(nums1[mid1]<nums2[mid2]){start1=mid1+offset;end2=mid2;}else{return nums1[mid1];}}return min(nums1[start1],nums2[start2]);
}int findKthNum(vector<int>&arr1,vector<int>&arr2,int k){vector<int>longs=arr1.size()>=arr2.size()?arr1:arr2;//长数组vector<int>shorts=arr1.size()<arr2.size()?arr1:arr2;//短数组int shortLenth=shorts.size();int longLenth=longs.size();if(k<=shortLenth){//情况1小于短数组的长度return GetMidNum(shorts,0,k-1,longs,0,k-1);}
//情况二中的小情况1大于长数组的长度if(k>longLenth){if(shorts[k-longLenth-1]>=longs[longLenth-1]){//手动验证return shorts[k-longLenth-1];}if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){//手动验证return longs[k-shortLenth-1];}
//算法原型return GetMidNum(shorts,k-longLenth,shortLenth-1,longs,k-shortLenth,longLenth-1);}
//情况二中的小情况1:大于短数组的长度但是小于短数组的长度if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){//手动排除长数组中的一个return longs[k-shortLenth-1];}return GetMidNum(shorts,0,shortLenth-1,longs,k-shortLenth,longLenth-1);
}int main(){int N,M,k;cin>>N>>M>>k;vector<int>arr1(N);for(int i=0;i<N;i++){cin>>arr1[i];}vector<int>arr2(M);for(int i=0;i<M;i++){cin>>arr2[i];}cout<<findKthNum(arr1, arr2, k);return 0;
}

有了上面的基础我们用这个题来秒杀几个题:

对应牛客网链接:多数组中位数_牛客题霸_牛客网 (nowcoder.com)

题目描述:

给定两个升序的数组 arr1 和 arr2 ,求两个数组合并后的下中位数

注意:下中位数指在两个数组的数个数在偶数时取更小的

输入:

[1,2,3],[3,4,5]

返回值:

3

输入:

[1,2,3],[4,5]

复制返回值:

3

解题思路:假设两个数组的总长度为len。如果len为偶数则下中位数为第len/2小的数,如果为奇数则为第len/2+1小的数

对应代码:

class Solution {
public:int getUpMedian(vector<int>& arr1, vector<int>& arr2) {// write code hereint len=(arr1.size()+arr2.size())/2;if(((arr1.size()+arr2.size())&1)==0){//判断奇数还是偶数长度len--;}return findKthNum(arr1,arr2, len+1);}int GetMidNum(vector<int>&nums1,int start1,int end1,vector<int>&nums2,int start2,int end2){int mid1=0;int mid2=0;int offset=0;while(start1<end1){mid1=(end1+start1)/2;mid2=(end2+start2)/2;offset=((end1-start1+1)&1)^1;if(nums1[mid1]>nums2[mid2]){end1=mid1;start2=mid2+offset;}else if(nums1[mid1]<nums2[mid2]){start1=mid1+offset;end2=mid2;}else{return nums1[mid1];}}return min(nums1[start1],nums2[start2]);
}
int findKthNum(vector<int>&arr1,vector<int>&arr2,int k){vector<int>longs=arr1.size()>=arr2.size()?arr1:arr2;vector<int>shorts=arr1.size()<arr2.size()?arr1:arr2;int shortLenth=shorts.size();int longLenth=longs.size();if(k<=shortLenth){return GetMidNum(shorts,0,k-1,longs,0,k-1);}if(k>longLenth){if(shorts[k-longLenth-1]>=longs[longLenth-1]){return shorts[k-longLenth-1];}if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){return longs[k-shortLenth-1];}return GetMidNum(shorts,k-longLenth,shortLenth-1,longs,k-shortLenth,longLenth-1);}if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){return longs[k-shortLenth-1];}return GetMidNum(shorts,0,shortLenth-1,longs,k-shortLenth,k-1);
}
};

我们再来看:

对应letecode链接:

https://leetcode-cn.com/problems/median-of-two-sorted-arrays/submissions/

题目描述:

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000

提示:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

解题思路和上题一样:会了前面两个题这两个题可以秒杀

对应代码:

class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int len=(nums1.size()+nums2.size());bool even=(len&1)==0;//判断是奇数还是偶数if(nums1.size()!=0&&nums2.size()!=0){if(even){return ( findKthNum(nums1,nums2,len/2)+findKthNum(nums1,nums2,len/2+1) )/2.0;//中间两个除二}else{//奇数return findKthNum(nums1,nums2,len/2+1);}}if(nums2.size()==0){if(even){return(double) (nums1[(len-1)/2]+nums1[len/2])/2;}else{return nums1[len/2];}}else if(nums1.size()==0){if(even)return(double)(nums2[(len-1)/2]+nums2[len/2])/2;else{return nums2[len/2];}}//数组长度都为0else{return 0;}}int GetMidNum(vector<int>&nums1,int start1,int end1,vector<int>&nums2,int start2,int end2){int mid1=0;int mid2=0;int offset=0;while(start1<end1){mid1=(end1+start1)/2;mid2=(end2+start2)/2;offset=((end1-start1+1)&1)^1;if(nums1[mid1]>nums2[mid2]){end1=mid1;start2=mid2+offset;}else if(nums1[mid1]<nums2[mid2]){start1=mid1+offset;end2=mid2;}else{return nums1[mid1];}}return min(nums1[start1],nums2[start2]);
}
int findKthNum(vector<int>&arr1,vector<int>&arr2,int k){vector<int>longs=arr1.size()>=arr2.size()?arr1:arr2;vector<int>shorts=arr1.size()<arr2.size()?arr1:arr2;int shortLenth=shorts.size();int longLenth=longs.size();if(k<=shortLenth){return GetMidNum(shorts,0,k-1,longs,0,k-1);}if(k>longLenth){if(shorts[k-longLenth-1]>=longs[longLenth-1]){return shorts[k-longLenth-1];}if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){return longs[k-shortLenth-1];}return GetMidNum(shorts,k-longLenth,shortLenth-1,longs,k-shortLenth,longLenth-1);}if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){return longs[k-shortLenth-1];}return GetMidNum(shorts,0,shortLenth-1,longs,k-shortLenth,k-1);
}};

如果觉得对您有帮助的话劳烦您点个赞,如有错误请在评论区留言

求两个有序数组中的中位数和第k小的元素相关推荐

  1. 【分步详解】两个有序数组中的中位数和Top K问题

    我现在在做一个叫<leetbook>的开源书项目,把解题思路都同步更新到github上了,需要的同学可以去看看 地址:https://github.com/hk029/leetcode 这 ...

  2. 寻找两个有序数组中的中位数

    1.题目描述 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2.请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)).你可以假设 nums1 和 n ...

  3. LeetCode4.python实现:寻找两个有序数组中的中位数问题☆☆☆

    目录 问题 解题思路 python具体实现 题外话 问题 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log( ...

  4. 用四种方法Python求出两个有序数组中的中位数

    方法一: def median_1(A, B):# 思路一: 先组合成一个有序数列,再取中位数# 时间复杂度O(m+n)len_A = len(A)len_B = len(B)C = []if len ...

  5. 找两个有序数组中的中位数---分治法实验1

    问题描述 设X[ 0 : n - 1]和Y[ 0 : n – 1 ]为两个数组,每个数组中含有n个已排好序的数.找出X和Y的2n个数的中位数. 编程任务 利用分治策略试设计一个O (log n)时间的 ...

  6. 求两个有序数组的中位数或者第k小元素

    问题:两个已经排好序的数组,找出两个数组合并后的中位数(如果两个数组的元素数目是偶数,返回上中位数). 设两个数组分别是vec1和vec2,元素数目分别是n1.n2. 算法1:最简单的办法就是把两个数 ...

  7. 取出两个有序数组里面的公共元素 java_C语言计算两个有序数组中的公共元素

    求两个有序数组的共同元素,比如数组a={1,2,3,8,9}和b={8,9,10},则输出output={8,9} // 找出两个数组的共同元素 int* FindCommon(int* a, int ...

  8. 利用分治法求两个有序数组的中位数

    也是看了一篇很好的博客,思路很清晰,只是有些地方感觉博主没有详细解释,后来理解了,做了一个小总结.原博客链接:点击打开链接 题目还是昨天的那道题目: 给定两个大小为 m 和 n 的有序数组 nums1 ...

  9. 求两个有序数组的中位数

    leetcode: 4 Median of Two Sorted Arrays 题目:给两个有序数组,长度为n和m,在 O(log (m+n))时间内找出两个数组中所有数字的中位数. 题解(参考讨论区 ...

最新文章

  1. CVCode简繁转换的扩展:GBK与Big5转换
  2. 【SCOI 2009】生日快乐
  3. mysql主程序目录_MySQL™ 参考手册(目录)
  4. 键盘按下某键 停止运行java_实现按下一个键执行操作/松开一个键停止操作
  5. 粤教版管理计算机中的文件教案,最新粤教版初中信息技术第一册教案(全册).docx...
  6. 优酷播控实践:基于规则引擎的投放管控模型
  7. 三次握手和四次挥手之间的关系
  8. 语言怎么绘画人物肖像_国画里的新年,看看古人是怎么过年的!
  9. avalon2学习教程15指令总结
  10. JAVA NIO基础知识
  11. 【Level 08】U08 Positive Attitude L5 Satisfy your need to know
  12. webstrom中使用git
  13. python能做什么工作-谁适合学Python?学了Python可以做什么工作?
  14. 【算法】1436. 旅行终点站(多语言实现)
  15. ES新特性之Reflect对象
  16. 超爽的对战游戏3.0版本来了 非常有趣
  17. 在线阅读.epub文件的网站
  18. Python-混合高斯分布(GMM)的应用及K-S检验
  19. Genesis创世纪
  20. 华为VRRP双机热备(基于接口设置热备)

热门文章

  1. Python实现自动翻译,手把手教学,适合任何水平,就算是零基础代码也能轻易运行
  2. a22_scala 伴生对象 伴生类
  3. MBR引导程序源码理解
  4. Ceres2.1 GPU加速的开始
  5. uni-app 之 跨平台开发
  6. 在CSDN上消失的一年
  7. 使用IDEA调试debug小技巧
  8. 【架构】1019- 6种事件驱动的架构模式
  9. 12 - 集合之间的并集与交集
  10. 现代营销杂志现代营销杂志社现代营销编辑部2022年第11期目录