2011考研题:求两个等长升序序列的中位数 ← 减治法

【题目来源】
https://www.acwing.com/problem/content/description/3822/

【问题描述】
一个长度为 L(L≥1)的升序序列 S,处在第 ⌈L/2⌉ 个位置的数称为 S 的
中位数
两个序列的中位数是含它们所有元素的升序序列的中位数。
例如,若序列 S1=(11,13,15,17,19),S2=(2,4,6,8,20),则 S1 和 S2 的中位数是 11。

现在有两个等长升序序列 A 和 B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列 A 和 B 的中位数。

【数据范围】
两个序列的长度均不超过 10^5。
序列中的元素取值范围 [−10^9,10^9]。

【算法分析】
分别求出序列A和B的中位数,记为a和b,有下列三种情况:

(1) 若a=b,则a或b即为两个序列的中位数,算法结束。
(2) 若a<b,则中位数只能出现在a和b之间,则舍弃序列A中较小的一半,同时舍弃序列B中较大的一半,并且要求舍弃的长度相等。
(3) 若a>b,则中位数只能出现在b和a之间,则舍弃序列A中较大的一半,同时舍弃序列B中较小的一半,并且要求舍弃的长度相等。
重复上述过程,直至两个序列都只有一个元素,则较小者为所求。


【算法代码一】

#include <iostream>
using namespace std;

int findMed(int* a,int* b,int n) {
    int alow,ahigh,blow,bhigh,amid,bmid;
    alow=blow=0;
    ahigh=bhigh=n-1;
    while(alow!=ahigh || blow!=bhigh) {
        amid=(alow+ahigh)/2;
        bmid=(blow+bhigh)/2;
        if(a[amid]==b[bmid]) return a[amid];
        else if(a[amid]<b[bmid]) {
            if((alow+ahigh)%2==0) {
                alow=amid;
                bhigh=bmid;
            } else {
                alow=amid+1;
                bhigh=bmid;
            }
        } else {
            if((blow+bhigh)%2==0) {
                blow=bmid;
                ahigh=amid;
            } else {
                blow=bmid+1;
                ahigh=amid;
            }
        }
    }
    return a[alow]<b[blow]?a[alow]:b[blow];
}

int main(){
    int* a;
    int* b;
    int mid;
    int n;
    cin>>n;
    a=new int[n];
    b=new int[n];
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++) cin>>b[i];
    
    cout<<findMed(a,b,n)<<endl;

    return 0;
}



/*
in1:
5
11 13 15 17 19
2 4 6 8 20
out1:
11

int2:
5
3 5 10 11 13
15 16 17 19 20
out2:
13
*/

【算法代码二】

#include<bits/stdc++.h>
using namespace std;

int findMed(vector<int>& a,vector<int>& b) {
    vector<int> t;
    int le=0, ri=0;
    int n=a.size(), m=b.size();
    while(le<n && ri<m) {
        if(a[le]<=b[ri]) t.push_back(a[le++]);
        else t.push_back(b[ri++]);
    }
    while(le<n) t.push_back(a[le++]);
    while(ri<m) t.push_back(b[ri++]);
    le=0, ri=n+m-1;
    return t[(n+m)/2-1];
}

int main() {
    vector<int> a,b;
    int x;
    int n;
    cin>>n;
    for(int i=0; i<n; i++) {
        cin>>x;
        a.push_back(x);
    };
    for(int i=0; i<n; i++) {
        cin>>x;
        b.push_back(x);
    };

    cout<<findMed(a,b)<<endl;
    return 0;
}



/*
in1:
5
11 13 15 17 19
2 4 6 8 20
out1:
11

int2:
5
3 5 10 11 13
15 16 17 19 20
out2:
13
*/




【参考文献】
https://www.acwing.com/solution/content/59699/
https://www.freesion.com/article/65131042399/
https://blog.csdn.net/ldanduo/article/details/8147113
https://www.cnblogs.com/VividBinGo/p/13100510.html

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值