二分查找模板

二分查找

(一)整数二分

二分的本质不是单调性,没有单调性也可以用二分
二分的本质是边界,在区间上定义某种性质,使得整个区间一分为二,一半区间满足这种性质,另一半区间不满足这种性质,那么二分可以寻找到性质的边界
在这里插入图片描述
既可寻找绿颜色边界,也可寻找红颜色边界
红色为不满足性质的区间,绿色为满足性质的区间

一.找满足性质的边界值(即绿色区间边界值)

1.找中间值mid=(l+r)>>1;
2.check(mid)满足性质时为true
3.如果check(mid)=true
说明在右边区间(绿色)找到了mid,应该到[l.mid]区间找答案
如果check(mid)=false
说明在左边区间(红色)找到了mid,应该到[mid+1,r]区间找答案

while(l<r){
    int mid=(l+r)>>1;
    if(check(mid)==true)r=mid
    else  l=mid+1;
}

二.找不满足性质的边界值(即红色区间边界值)

1.找中间值mid=(l+r+1)>>1;
当l=r-1时, 如果check为true l=mid mid=l+r>>1=l 会发生死循环
2.check(mid)不满足性质时为true
3.如果check(mid)=true
说明在左边区间(红色)找到了mid,应该到[mid,r]区间找答案
如果check(mid)=false
说明在右边区间(绿色)找到了mid,应该到[l,mid-1]区间找答案

while(l<r){
    int mid=(l+r+1)>>1;
    if(check(mid)l=mid;
    else r=mid-1;

}

归结上面的两种二分方法

步骤为:

先写一个check函数
判定在check的情况下(true和false的情况下),如何更新区间。
在check(m)==true的分支下是:
根据是l-mid还是r=mid判断到底是红色方法还是绿色方法
l=mid的情况, mid+1,中间点的更新方式是m=(l+r+1)/2
r=mid的情况,mid不用+1,中间点的更新方式是m=(l+r)/2
这种方法保证了:

  1. 最后的l==r
  2. 搜索到达的答案是闭区间的,即a[l]是满足check()条件的。

二分问题一定有解,通过二分判断出的性质导出原问题可能会无解。

例:check为>=t的l,r
返回第一个位置

int search(int t,int l,int r){
    while(l<r){
        int mid=(l+r)>>1;
        if(num[mid]>=t)r=mid;
        else l=mid+1;
    }
    printf("%d %d\n",l,r);
}

结果为:
在这里插入图片描述

例:check为<=t的l,r
返回最后一个位置

int searchr(int t,int l,int r){
    while(l<r){
        int mid=(l+r+1)>>1;
        if(num[mid]<=t)l=mid;
        else r=mid-1;
    }
    
    printf("%d %d\n",l,r);
}

在这里插入图片描述

最终返回结果l=r

例题 数的范围

在这里插入图片描述

#include <iostream>
using namespace std;
const int N=1e6;
int num[N];
int searchl(int t,int l,int r){
    while(l<r){
        int mid=(l+r)>>1;
        if(num[mid]>=t)r=mid;
        else l=mid+1;
    }
    if(num[l]!=t)return -1;
    else return l;
}
int searchr(int t,int l,int r){
    while(l<r){
        int mid=(l+r+1)>>1;
        if(num[mid]<=t)l=mid;
        else r=mid-1;
    }
    if(num[l]!=t)return -1;
    else return l;
}
int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    
    for(int i=0;i<n;i++){
       scanf("%d",&num[i]);
    }
    
    for(int i=0;i<q;i++){
        int t;
        scanf("%d",&t);
        int l=searchl(t,0,n-1);
        int r=searchr(t,0,n-1);
        if(l==-1||r==-1)printf("-1 -1\n");
        else printf("%d %d\n",l,r);
    }
    return 0;
    
    
    
    
    
}

(二) 浮点数二分

相对于整数二分没有边界问题,很好写

法一:用精度进行限制

while(r-l<1e-6){
    int mid=(l+r)>>1;
    if(check(mid))r=mid;
    else l=mid;
}

法二:直接迭代100次

for(int i=0;i<100;i++){
    int mid=(l+r)>>1;
    if(check(mid))r=mid;
    else l=mid;
}

例题 求数的三次方根

注意范围取值
当x^3=0.001 x=0.1
不能取[-x,x]作为区间,取max(1,x)
在这里插入图片描述

#include <iostream>
#include <math.h>
using namespace std;
double search(double x,double l,double r){
    
    while(r-l>=1e-7){
        double mid=(l+r)/2.0;
        if(mid*mid*mid>=x)r=mid;
        else l=mid;
    }
    return l;
}
int main(){
    double x;
    scanf("%lf",&x);
    double l=min(-1.0,x);
    double r=max(1.0,x);
    double ans=search(x,l,r);
    printf("%.6lf",ans);
    
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
javascript函数的解释,解释了具体函数的功能,一、函数JavaScript函数集合 1.document.write(""); 输出语句 2.JS中的注释为// 3.传统的HTML文档顺序是:document->html->(head,body) 4.一个浏览器窗口中的DOM顺序是:window->(navigator,screen,history,location,document) 5.得到表单中元素的名称和值:document.getElementById("表单中元素的ID号").name(或value) 6.一个小转大的JS: document.getElementById("output").value = document.getElementById("input").value.toUpperCase(); 7.JS中的值类型:String,Number,Boolean,Null,Object,Function 8.JS中的字符型转换成数值型:parseInt(),parseFloat() 9.JS中的数字转换成字符型:(""+变量) 10.JS中的取字符串长度是:(length) 11.JS中的字符与字符相连接使用+号. 12.JS中的比较操作符有:==等于,!=不等于,>,>=,<.<= 13.JS中声明变量使用:var来进行声明 14.JS中的判断语句结构:if(condition){}else{} 15.JS中的循环结构:for([initial expression];[condition];[upadte expression]) {inside loop} 16.循环中止的命令是:break 17.JS中的函数定义:function functionName([parameter],...){statement[s]} 18.当文件中出现多个form表单时.可以用document.forms[0],document.forms[1]来代替. 19.窗口:打开窗口window.open(), 关闭一个窗口:window.close(), 窗口本身:self 20.状态栏的设置:window.status="字符"; 21.弹出提示信息:window.alert("字符"); 22.弹出确认框:window.confirm(); 23.弹出输入提示框:window.prompt(); 24.指定当前显示链接的位置:window.location.href="URL" 25.取出窗体中的所有表单的数量:document.forms.length 26.关闭文档的输出流:document.close(); 27.字符串追加连接符:+= 28.创建一个文档元素:document.createElement(),document.createTextNode() 29.得到元素的方法:document.getElementById() 30.设置表单中所有文本型的成员的值为空: var form = window.document.forms[0] for (var i = 0; i<form.elements.length;i++){ if (form.elements[i].type == "text"){ form.elements[i].value = ""; } } 31.复选按钮在JS中判断是否选中:document.forms[0].checkThis.checked (checked属性代表为是否选中返回TRUE或FALSE) 32.单选按钮组(单选按钮的名称必须相同):取单选按钮组的长度document.forms[0].groupName.length 33.单选按钮组判断是否被选中也是用checked. 34.下拉列表框的值:document.forms[0].selectName.options[n].value (n有时用下拉列表框名称加上.selectedIndex来确定被选中的值) 35.字符串的定义:var myString = new String("This is lightsword"); 36.字符串转成大:string.toUpperCase(); 字符串转成小:string.toLowerCase(); 37.返回字符串2在字符串1中出现的位置:String1.indexOf("String2")!=-1则说明没找到. 38.取字符串中指定位置的一个字符:StringA.charAt(9); 39.取出字符串中指定起点和终点的子字符串:stringA.substring(2,6); 40.数学函数:Mat

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值