顺序表 | 二分查找:两个数组合并后的中位数

王道P18 T11

输入两个长度相同的升序数组,返回这两个数组合并后的中位数

C++代码:

int bisearch_midNum(int a[],int b[],int n){
    int s1=0,s2=0,d1=n-1,d2=n-1,m1,m2;
    while(s1!=d1 || s2!=d2){//只要a,b序列同时出现了s==d的情况,才能False退出
        m1=(s1+d1)/2;
        m2=(s2+d2)/2;
        system("pause");
        if(a[m1]==b[m2])
            return a[m1];
        else if(a[m1]<b[m2]){//∈[m1,m2]
            d2=m2;
            if((d1-s1)%2){//偶数
                m1++;//舍去中间位
            }
            s1=m1;
        }else{               //∈[0,m1]∪[m2,n]
            d1=m1;
            if((d2-s2)%2){//偶数
                m2++;//舍去中间位
            }
            s2=m2;
        }
    }
    //返回较小者
    return min(a[s1],b[s2]);
}

 完整代码:

#include <cstdio>
#include <memory.h>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>
#include <stdlib.h>
#include <time.h>


#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 200
#define MAX 0x7FFFFFFF

using namespace std;

void disp(int * sqList,int length);
int bisearch_midNum(int a[],int b[],int n);

int main() {
    while(1){
        srand((unsigned)time(NULL));
        int a[20];
        int *b=a+10;
        for(int i=0;i<10;i++){a[i]=rand()%20;b[i]=rand()%20;}

        sort(a,a+10);
        sort(b,b+10);
        OL("a:");
        disp(a,10);
        OL("b:");
        disp(b,10);

        O("mid number:");
        O("%d

",bisearch_midNum(a,b,10));

        sort(a,a+20);
        OL("merge:");
        disp(a,20);
        system("pause");
        system("cls");
    }

}


void disp(int * sqList,int length){
    int i=0;
    FF(i,length){
        printf("%d	",sqList[i]);
    }
    OL("");
}


int bisearch_midNum(int a[],int b[],int n){
    int s1=0,s2=0,d1=n-1,d2=n-1,m1,m2;
    while(s1!=d1 || s2!=d2){//只要a,b序列同时出现了s==d的情况,才能False退出
        m1=(s1+d1)/2;
        m2=(s2+d2)/2;
        printf("%d %d %d
",s1,d1,m1);
        printf("%d %d %d
",a[s1],a[d1],a[m1]);
        printf("%d %d %d
",s2,d2,m2);
        printf("%d %d %d
",b[s2],b[d2],b[m2]);
        system("pause");
        if(a[m1]==b[m2])
            return a[m1];
        else if(a[m1]<b[m2]){//∈[m1,m2]
            d2=m2;
            if((d1-s1)%2){//偶数
                m1++;//舍去中间位
            }
            s1=m1;
        }else{               //∈[0,m1]∪[m2,n]
            d1=m1;
            if((d2-s2)%2){//偶数
                m2++;//舍去中间位
            }
            s2=m2;
        }
    }
    //返回较小者
    return min(a[s1],b[s2]);
}
View Code

一步一调理解此题:

●第一组数据:

 第一步:a→  ←b

(如果【s1,d1】是偶数,就舍弃m1,即(m1,d1])

第二步:a→  ←b

第三步:←a b→

第四步:←a b→

b的中位数取9是因为【←a b→】这种情况要舍弃左边的m。

m1==s1,m2==s2,终止。在a【s1】与 b【s2】中取最小者,即6。

两个数组融合后的中位数也为6:


 我的一些理解:

1.关于偶数时舍弃m:

在迭代的最后,a,b中都只剩下两个元素。

情况1:a→  ←b

这时候b的m会自动定位到左边然后==s1,但是a的m也会往左定位,就不满足a→ 了。所以要舍弃m。

情况2: ←b a→

同理可得。

2.关于返回较小的变量:

如图,此时有两个候选变量,一个是6,一个是9。因为二分搜索的性质,在偶数的情况下,其实定位的m是那个偏小的元素,并且输入的数组都是升序。


感悟:

感觉这题难爆了,只能想出O(N)的算法。本题的思想是用了两个数组都是升序的特点,通多二分查找找到两个尽可能相等的数a[m1]和b[m2] 。

原文地址:https://www.cnblogs.com/TQCAI/p/8168812.html