408计算机学科基础综合2014 年 42 题真题讲解

42 .( 15 分)一个长度为 L L 1 )的升序序列 S ,处在第 L /2 个位置的数称为 S 的中
位数。例如,若序列 S1 = (11, 13, 15, 17, 19) ,则 S1 的中位数是 15 ,两个序列的中位数是含
它们所有元素的升序序列的中位数。例如,若 S2 = (2, 4, 6, 8, 20) ,则 S1 S2 的中位数是 11
现在有两个等长升序序列 A B ,试设计一个在时间和空间两方面都尽可能高效的算法,找出
两个序列 A B 的中位数。要求:
1 )给出算法的基本设计思想。
2 )根据设计思想,采用 C C++ Java 语言描述算法,关键之处给出注释。
3 )说明你所设计算法的时间复杂度和空间复杂度。
答案解析:
这个题目所考察的内容是二分查找,但是有两个数组,是双数组的二分查找,是一道非常经
典的题目。因为空间尽可能高效,因此我们不能够去再搞一个大数组,把两个数组合并到一
起,这样得分会非常低。
1 )算法的基本设计思想如下:
分别求出序列 A 和 B 的中位数,设为 a 和 b,求序列 A 和 B 的中位数过程如下:
1)若 a=b,则 a 或 b 即为所求中位数,算法结束。
2)若 a<b,则舍弃序列 A 中较小的一半,同时舍弃序列 B 中较大的一半,要求舍弃的
长度相等;
3)若 a>b,则舍弃序列 A 中较大的一半,同时舍弃序列 B 中较小的一半,要求舍弃
的长度相等;
在保留的两个升序序列中,重复过程 1)、2)、3),直到两个序列中均只含一个元素
时为 止,较小者即为所求的中位数。
#include <stdio.h>
int MidSearch(int A[], int B[], int n) {
//分别表示序列 A 和 B 的首位数、末位数和中位数,s 是 start 简写,d 是 end 简写
int s1 = 0, d1 = n - 1, m1, s2 = 0, d2 = n - 1, m2;
//循环判断结束条件是,两个数组均不断删除最后均只能剩余一个元素
while (s1 != d1 || s2 != d2) {
    m1 = (s1 + d1) / 2;
    m2 = (s2 + d2) / 2;
if (A[m1] == B[m2])
    return A[m1]; //满足条件 1)
if (A[m1] < B[m2]) { //满足条件 2)
if ((s1 + d1) % 2 == 0) { //若元素个数为奇数,这里注意数组下标从 0 开始
    s1 = m1; //舍弃 A 中间点以前的部分且保留中间点
    d2 = m2; //舍弃 B 中间点以后的部分且保留中间点
}
else { //元素个数为偶数
    s1 = m1 + 1; //舍弃 A 中间点及中间点以前部分,我们举一个例子告诉大家必须
加 1
    d2 = m2; //舍弃 B 中间点以后部分且保留中间点
}
}
else { //满足条件 3),下面的操作和上面条件 2 是完全对称的
if ((s1 + d1) % 2 == 0) { //若元素个数为奇数
    d1 = m1; //舍弃 A 中间点以后的部分且保留中间点
    s2 = m2; //舍弃 B 中间点以前的部分且保留中间点
}
else { //元素个数为偶数
    d1 = m1; //舍弃 A 中间点以后部分且保留中间点
    s2 = m2+1; //舍弃 B 中间点及中间点以前部分
}
}
}
return A[s1] < B[s2] ? A[s1] : B[s2];//因为题目要的是 11,因此我们拿小的那个
}
int main()
{
    int A[] = { 11,13,15,17,19};//我们也可以分别把 A 和 B 都变为偶数个元素来测试
    int B[] = { 2,4,6,8,20};
    int mid = MidSearch(A, B, 5);
    printf("mid=%d\n", mid);
    return 0;
}
算法的时间复杂度为 O(log 2 n),空间复杂度为 O(1)。
因为我们没有使用额外的跟 n 相关的空间,因为不断的二分,次数是 log 2 n,所以时间
复杂度是 O(log 2 n)
  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值