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


    王道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] 。

  • 相关阅读:
    “error LNK1169: 找到一个或多个多重定义的符号”的解决方法(转载)
    std::ostringstream 转std::string
    【转载】红外感应模块+蜂鸣器实现简易报警
    分割字符串使用空格
    优秀程序员的 18 大法则【转载】
    解决win10 iot VS编程出现的无法引用错误
    [转载] 程序员如何成功追到女神?
    win8/win10/win2012r2 存储池 冗余分析
    [转载][NAS] 使用win8的“存储池”功能~
    mySQL中删除unique key的语法 (删除某个字段的唯一性)
  • 原文地址:https://www.cnblogs.com/TQCAI/p/8168812.html
Copyright © 2020-2023  润新知