zoukankan      html  css  js  c++  java
  • 递增整数序列的二分详解

    二分搜索是一种时间复杂为log2n的算法,可以用于单调函数求根和单调序列查询的有效算法,即使数列长度高达10^9 也只需二分31次,查询速度接近常数,同时二分思想是一种很基础很重要的思想希望同学们都能掌握;

    单调数列(单调递增)通用二分模板

    简洁版

    完全版

    start_index =0end_index=len-1时,功能和简洁版一样;

    1.

    为啥不能写下面这句

    ifmid==n

    return mid

    因为有时候会有

    这样的一种数列

    1 2 2 2 2 3

    这个是非严格单调序列,如果叫你寻找2第一次出现的位置显然会出现错误

    所以上面那个写法是不行的;

    2.

    为啥不写left=mid+1right=mid-1

    因为有些情况下会不能用

    比如在数列

    a[]={0 1 3 4,5}

    找大于2的第一个位置

    当你right=4left=0;

    mid=2A[mid]>2 所以 若r=mid-1=1你就错过去了,除非你用if判断一下,但那样就太冗长难看了;

    3.

    为啥不能写

    while(left=right)

    因为上面的原因我们没用 left=mid+1right=mid-1

    而是left=mid,right=mid

    a[]={0,1,3,4};

    则找2的位置时会死循环

    因为 left=1right=2

    mid=(left+right)/2=1

    a[mid]<2;

    所以left=mid=1

    结果left还是等于1right还是等于2

    永远死循环

    现在来解释一下上面代码的原理:

    我们让left代表小于等于 x的一方

           right代表大于x的一方

    我们每次判断mid是属于left还是属于right来使区间缩小一半;

    leftright相遇时,即left+1=right时 分界线就在leftright中间

    则从left开始往前小于等于x,right开始往后大于x

    同理其实我们也可以让

    iff(mid)<x

    left=mid;

    else

    right=mid;

    这时

    left代表小于x的一方

             right代表大于等于x的一方

    leftright相遇时;

    则从left开始往前小于x,right开始往后大于等于x

    即如图所示

    最后我们来教点小技巧

    如果我把前一种记做find_upper_bound()

     

    如果我把后一种记做find_lower_bound()

    显然图观察可得 两种的二分结果分别是

    x的下标上界和下标下界(包含x

    他们相减就是x的个数

    显然若find_upper_bound(x)==find_lower_bound(x);那么就不存在x

    在使用时不用写两种二分,其实由观察图可得

    find_upper_bound(x-1)=find_lower_bound(x);

    或者find_upper_bound(x)=find_lower_bound(x+1);

    所以其实写一种就行了;

    这里给出对照表(前提是整数递增序列才成立,如果是浮点数或则递减序列时都不成立)

    查询目标            find_upper_bound的用法    find_lower_bound的用法

    大于x的第一个位置        find_upper_bound(x)     find_lower_bound(x+1)

    x出现的第一个位置        find_upper_bound(x-1)    find_lower_bound(x)

    小于x的第一个位置        find_upper_bound(x-1)-1   find_lower_bound(x)-1

    x出现的最后位置         find_upper_bound(x)-1    find_lower_bound(x+1)-1

    习题

    1.http://210.34.193.66:8080/vj/Problem.jsp?pid=2145

    2.http://210.34.193.66:8080/vj/Problem.jsp?pid=1923(这题注意要先用快速排序再二分)

    这里是习题1的标程

  • 相关阅读:
    innerHTML和innerText
    Function 构造器及其对象、方法
    构造函数
    jquery 获取及设置input各种类型的值
    在浏览器中输入URL并回车后都发生了什么?
    :after和:before的作用及使用方法
    使用JS监听键盘按下事件(keydown event)
    Javascript模块化编程(三):require.js的用法
    Javascript模块化编程(二):AMD规范
    Javascript模块化编程(一):模块的写法
  • 原文地址:https://www.cnblogs.com/qswg/p/6251887.html
Copyright © 2011-2022 走看看