• 二分搜索专题(1)


    先附个经典二分搜索代码

    int BinarySearch(int arr[],int N,int target)
    {
        int p=0;
        int r=N-1;
        while(p<=r){
            int q=r-(r-p)/2;
            if(arr[q]==target) return q;
            else if(arr[q]<target) p=q+1;
            else r=q;
        }
        return -1;
    }

    1.考察要点

    1.二分搜索不仅在有序序列中可以运用,无序序列也同样适用只要满足每次查找都会缩小一半查找范围

    2.注意循环初始条件,边界值,划分点的处理,确保循环不会无法终止

    3.划分点的经典写法:(p+r)/2 ,安全写法:r-(r-p)/2或p+(r-p)/2

    2.局部最小值问题

      问题描述:在一个无序序列中,且任意两个相邻元素都不相等的情况下,查找满足arr[i]<arr[i+1]且arr[i]<arr[i-1]的元素。

      查找方法:

        1.arr为空或长度为1时返回。

        2.判断两端点的情况

          如果端点值中有一个端点是局部最小值,则立即返回。

        3.端点两边都不是局部最小,如下,讨论中间点mid。

          

        4.中间点的情况

          1.当属于情况2时,直接返回mid.

          2.否则,如3的两边,4的左边,比存在局部最小值,因为相邻元素不同,以4的左边为例,

          在mid的左边,一旦出现上升点,则此点局部最小,否则若一直向左降序,则arr[1]为局部最小值。

          3.未画出的情况5参考情况4。

          

    附一个查找局部最小元素的代码

    int BinarySearch2(int arr[],int p,int r)
    {
        //if(p>r) return -1;
        if(p==r) return p;
        if(arr[p]<arr[p+1]) return p;
        if(arr[r]<arr[r-1]) return r;
        int q=r-(r-p)/2;
        if(arr[q]<arr[q-1]){
            if(arr[q]<arr[q+1]) return q;
            return BinarySearch2(arr,q+1,r);
        } else{
            return BinarySearch2(arr,p,q-1);
        }
    }

     3.含有重复元素的有序数组问题

       问题描述:给定有序数组arr,num,查找num在arr中出现的最左的位置。

       举例分析:num=3,arr={1,2,3,3,4,4,4,4,4}

           1.初始状态:res=-1,arr={1,2,3,3,4,4,4,4,4}

           2.mid=4,arr={1,2,3,3},res=-1;

           3.mid=2,arr={3,3},res=-1;

           4.mid=3左,arr={},返回res=2.

       总结:维护一个res,当找到num时,继续向左找,直到要找部分为空。

    附一个查找最右元素的代码  

    int BinarySearch1(int arr[],int p,int r,int target,int res)
    {
        if(p>r) return res;
        int q=(p+r)/2;
        if(arr[q]==target) return BinarySearch1(arr,q+1,r,target,q);
        else if(arr[q]<target) return BinarySearch1(arr,q+1,r,target,res);
        else return BinarySearch1(arr,p,q-1,target,res);
    }

    4.求有序循环序列的最小元素

     对于数组L.....R,如{4,5,6,0,1,2,2,3}

     1.如果arr[L]<arr[R],则返回arr[L]

     2.如果arr[M]>arr[R],则最小值位于M...R

     3.如果arr[M]<arr[L],则最小值位于L...R

     4.如果arr[L]<=arr[M]<=arr[R],又arr[L]>=arr[R],故arr[L]=arr[R]=arr[M],此时只能遍历求得最小值。

     5.由于划分元素不会被裁去,需要重新处理边界值问题(此题当元素个数为2时继续循环不会减少)。

    附一个查找最小元素的代码

    int BinarySearch3(int arr[],int N)
    {
        int p=0;
        int r=N-1;
        while(1){
             if(r-p == 1) return arr[r];
            if(arr[p]<arr[r]) return arr[p];
            int q=r-(r-p)/2;
            if(arr[q]<arr[p]) r=q;
            else if(arr[q]>arr[r]) p=q;
            else{
                int m=arr[p];
                for(int i=p+1;i<=r;i++) m=m<arr[i]?m:arr[i];
                return m;
            }
        }
            return -1;
    }

    5.求有序无重复元素的最左原位

    1.定义:最左原位:满足arr[i]=i的最左位置i

    2.步骤:

        初始化res=-1

      1.如果arr[0]>N-1或arr[N-1]<0,返回-1

      2.如果arr[M]<M,则左边排除,搜索0...M-1(这是因为数组有序且不重复,故左半部分最低与i减少速度相同,故arr[i]恒小于i

         如果arr[M]>M,则右边排除,搜索M+1...N-1

      3.如果arr[M]=M,更新res,由于找最左原位,故继续向左找

      4.重复1-3,直到待查找序列空。

    附一个查找最左原位

    int BinarySearch4(int arr[],int N)
    {
        int res=-1;
        int p=0;
        int r=N-1;
        while(p<=r){
            int q=r-(r-p)/2;
            if(arr[p]>r) return res;
            if(arr[r]<p) return res;
            else if(arr[q]>q) r=q-1;
            else if(arr[q]<q) p=q+1;
            else {
                res=q;
                r=q-1;
            }
        }
        return res;
    }
  • 相关阅读:
    自定义Visual Studio调试器中的对象显示方式
    Visual Studio中的主题定制变得更加容易
    宣布Visual Studio Code Installer for Java
    在Visual Studio 2019中开启预览功能
    .NET Core 3.0预览版7中的ASP.NET Core和Blazor更新
    C#连接SQL Anywhere 12 数据库
    数据库导出脚本
    python http请求及多线程应用
    记录 Ext 日历月份选择控件bug解决过程结果
    js浮点数运算封装, 起因财务部分精确计算
  • 原文地址:https://www.cnblogs.com/lshao/p/8970563.html
Copyright © 2020-2023  润新知