(C语言)【2011统考真题】两个序列的中位数是含他们所有元素的升序序列的中位数,现有两个等长升序序列A和B求他们的中位数,要求时间和空间尽可能高效的算法

这个题目的时间复杂度最小可以是O(logn);

解析:设A=(11,13,15,17,19)B=(2,4,6,8,20)
第一种想法:把A和B混合到一起再找中位数,这时候时间复杂度是O(n);
第二种想法:将中位数左右两边依次同时减去等长的元素,中位数不变。

A的中位数是15B的中位数是6;因为A和B都是等长升序序列,说明A和B混合之后的中位数 6<=Mid<=15这时候将6的左边和15的右边删去相同数目也就是
A=(11,13,15);B=(6,8,20)

//这个两个数组合并的中位数和之前A=(11,13,15,17,19)
B=(2,4,6,8,20)合并的中位数一样

此时A的中位数是13B的中位数是8;同理
Mid的范围缩小为 8<=Mid<=13 左右删去相同的数量的元素
A=(11,13);B=(8,20)
此时A的中位数是11B的中位数是8
偶数情况下,下面有解释)8<Mid<=11 此时当删去13时8的左边没有元素为了保持平衡应该删去8;
此时A=(11);B=(20);所以A和B序列的中位数是11

【当序列分别为偶数时中位数不可能等于A和B较小的中位数
因为例如A的中位数大,A的右侧的数包括A比左侧的数大2,A和B合并后最理想的可能A的中位数的左侧全部比B的中位数小,即使这样合并后B的中位数的右边的数的个数要比左边的数的个数大2;图示:
A=(1,2,6,7,8,9);B=(3,4,5,10,11,12)
A和B(1,2,3,4,5,6,7,8,9,10,11,12)
这样合并后5右边的数的个数要比左边的数的个数大2,而偶数序列中位数右边要比左边大1,所以不可能是B的中位数

代码如下:

int Search(int A[], int B[], int n) {
	int s1 = 0, d1 = n - 1, m1;//A的首位数、中位数、末位数
	int s2 = 0, d2 = n - 2, m2;//B的首位数、中位数、末位数
	while (s1 != d1 || s2 != d2) {
		m1 = (s1 + d1) / 2;
		m2 = (s2 + d2) / 2;
		if (A[m1] == B[m2]) //当两个中位数相等,即为所求中位数
			return A[m1];
		else if (A[m1] < B[m2]) {
			if ((s1 + d1) % 2 == 0) { //当元素个数为奇数
				s1 = m1;              //舍弃A中间点以前部分,保留中间点
				d2 = m2;              //舍弃B中间点以后部分,保留中间点
			}
			else{                      //当元素个数为奇数
				s1 = m1 + 1;           //舍弃A中间点以前部分,不保留中间点
				d2 = m2;               //舍弃B中间点以后部分,保留中间点
			}
			
		}
		else {
			if ((s2 + d2) % 2 == 0) {
				d1 = m1;
				s2 = m2;
			}
			else {
				d1 = m1;
				s2 = m2 + 1;
			}
		}

	}
	return A[s1] < B[s2] ? A[s1] : B[s2];
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值