(详解)11年真题:求两个序列合并后的的中位数

(2011年真题)长度为L的升序序列S,在第(L/2)个位置的数称为S的中位数,注意:向上取整,也就是说L=5,则第三个是中位数,两个序列的中位数是指两个序列合并后的的中位数。现给出等长升序序列A和B,试着设计算法,找出A和B的中位数
  • 1)给出算法的设计思路
  • 2)用c/c++/java描述算法
  • 3)说明空间复杂度和时间复杂度

这个题利用二分查找做,我觉得答案的算法还是比较容易想明白的
但是如果要讲的话,不太好讲,所以解析写的不太好,凑合看,大概就是这么个意思~

解析:(若不想看解析,直接拉到下边是答案)

这个问题可能很多人会想到一种方法,因为是升序序列,两个序列合并后长度是2L,我们边扫描边比较并计数,需要比较L次即可得到中位数,也就是说时间复杂度为O(n),其实也比较优秀了,但是还有更好的方法
因为是升序,我们类似二分查找的思想,我们用来查找中位数,每次舍弃不符合条件的部分
所以关键问题是判断出不符合条件的的部分

首先我们要明确
两个数列合并后,长度为偶数2L,我们要求的中位数,其实就是第L个数字
也就是前一半序列的最后一个数字,
也就是说合并后一定有L-1个数字小于等于中位数,一定有L个数字大于等于中位数,这是必须符合的条件
我们先分别找到这两个序列的中位数,记作a,b
但是注意,两个序列长度都是L,L的奇偶性所得到的中位数是不一样的
在这里插入图片描述
然后我们要分两种情况讨论

(1)L为奇数的时候

在这里插入图片描述
因为是升序序列,所以a,b前边的数都比他们小
因为L是奇数,所以很容易算出a,b前边共有(L-1)个数字,

  1. 若a=b 那说明前边的(L-1)个数都小于a或b,a,b必然是中位数
  2. 若a<b 那么对于a前边的(L-1)/2个数来说,他们都不可能是中位数
    因为a,b后边的(L-1)个数再加上a,b本身。一共L+1个数字,都比他们大
    同理,b后边的(L-1)/2个数字也不可能有中位数,舍弃这两部分
  3. 若a>b 和a<b是一样。

舍弃之后,你可以思考一下,我们把不可能是中位数的数舍弃了,其实这个操作相等于对于合并后的序列,掐头去尾
删除了前边和后边不可能是中位数的数字
那么剩下的,我们继续进行这样的操作,再掐头去尾,直到最后,一定会两个序列都只剩下一个数字,那么这两个数
较小的那个就是中位数(为什么是较小的呢?因为合并后长度是偶数,根据题意偶数的中位数偏前边~
注意一点:这个原理说明了,我们每次删除的前后必须长度一致
在这里插入图片描述

还需要注意的是:我们舍弃的时候,要不要连a,b一起舍弃呢?

这取决于a,b有没有可能是我们要求的中位数
上面我们说过,a<b时,a前边的数都不可能是,那么a有没有可能呢
显然,是有可能的,a前边(L-1)/2个数都小于a,若b前边的(L-1)/2个数也小于a,
那么a就是中位数了,且未破坏a<b的条件,所以a不能删除
但是b不可能是中位数,因为已知就有L个数小于b了,但是呢b也不能删,因为上边讲原理的时候说了你必须满足每次掐头去尾的长度一致,这样才能在留下的序列中继续找中位数
所以结论是:L为奇数是,舍弃时保留a,b

(2)L为偶数

L是偶数的话,很容易算出a,b前边共有(L-2)个数字,
在这里插入图片描述
a=b就不说了
a<b时,a不可能是中位数,因为已经存在(L+1)个数大于a(a后边的数+b后边的数+b本身)
所以a可以删除,b是有可能是中位数的,b不能删除,而且
偶数时你要保证掐头去尾的长度一致,就必须a,b留一个删一个,才能相等
故结论是: L为偶数时,舍弃时保留大的,删除小的
a>b 同理
在这里插入图片描述

答案:

设计思路:分别求出两个升序序列A、B的中位数a、b
1、若a=b 则a,b即为所求的中位数
2、若a<b 则舍弃A中较小的一半,同时舍去B中较大的一半,要求两次舍弃的长度相等
3、若a>b 则舍弃B中较小的一半,同时舍去A中较大的一半,要求两次舍弃的长度相等
在保留下来的两个升序序列中,重复上述三个步骤,直到两个序列中都只上一个元素为止,
较小的就是所求的中位数
算法描述:

int M_search(int A[],int B[],int n){
	int s1=0,d1=n-1,s2=0,d2=n-1,m1,m2;   //起点 终点 中间点 
	while(s1!=d1||s2!=d2){
		m1=(s1+d2)/2;
		m2=(s2+d2)/2;
		if(A[m1]==B[m2]) return A[m1];  //若相等 
		if(A[m1]<B[m2]){                //若a<b 
			if((s1+d1)%2==0){           //若长度是奇数 
				s1=m1;                  //删除a前边的并保留a 
				d1=m2;                  //删除b后边的并保留b 
			}
			else{                       //若长度是偶数 
				s1=m1+1;                //删除a以及a前边的 
				d2=m2;                  //删除b后边的并保留b 
			}
		}
		else{                           //a>b 与上边同理 互换操作即可 
			if((s2+d2)%2==0){
				d1=m1;
				s2=m2;
			}
			else{
				d1=m1;
				s2=m2+1;
			}
		}
	}
	return A[s1]<B[s2]?A[s1]:B[S2];
	
} 

复杂度分析:
每次舍弃的长度是总长度的一半,所以跟二分查找一样
时间复杂度O(logn) 空间复杂度O(1)
###############################################

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1900_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值