二分查找 & 二分答案 万字详解,超多例题,带你学透二分。

您所在的位置:网站首页 编程实现二分查找算法的方法是 二分查找 & 二分答案 万字详解,超多例题,带你学透二分。

二分查找 & 二分答案 万字详解,超多例题,带你学透二分。

2024-07-10 22:24| 来源: 网络整理| 查看: 265

很多人对二分感到很苦恼,很困惑,可能是因为二分的边界很难掌握,也许是判断条件难写…

然而,很幸运,你找到了这篇文章,仔细看下去,这篇文章将带你学透二分!!!

二分可以简单分为二分查找与二分答案。

可能你听说过二分查找,二分查找和二分答案是不是一回事呢?答案是否定的。二分查找只是单纯的查找就可以了,简单的控制好边界条件。而二分答案也许稍复杂些。

首先,我们看一下二分的模板: 模板1: while (l > 1; //(l+r)/2 if (check(mid)) r = mid; // check()判断mid是否满足性质 else l = mid + 1; } 模板2: while (l > 1; //(l+r+1)/2 if (check(mid)) l = mid; else r = mid - 1; }

看到这,以后的你就不会因为边界问题而困惑了!!!

第一个模板是尽量往左找目标,第二个模板是尽量往右找目标。

只要是往左找答案,就用第一个模板,mid不用加一,r=mid,l加一; 只要是往右找答案,就用第二个模板,mid要加一,l=mid,r要减一;

二分套这两个模板,肯定没错!(只要判断条件写对)亲测有效!!! 下面的题目更能证明这句话!

这两个模板一定要牢牢记住哦

当然,二分可能在实数中进行,那自然少不了浮点二分。

模板3:(浮点二分) while(r-l>1e-5) //需要一个精度保证 { double mid = (l+r)/2; if(check(mid)) l=mid; //或r=mid; else r=mid; //或l=mid; }

浮点二分就相对简单多了,因为浮点除法不会取整,所以mid,l,r,都不用加1或减1.

我们先来学二分查找:

二分查找也称折半查找,顾名思义,就是每次查找去掉不符合条件的一半区间,直到找到答案(整数二分)或者和答案十分接近(浮点二分)。

光说不练假把式,来个例题:

例题1——查找

在这里插入图片描述 分析:这题就是典型的二分查找入门题。

首先,区间是有单调性的,查找第一次出现的位置,如果查到一个值比目标值大,就把右半边放弃,因为右半边肯定也比目标值大;同样,如果查到值比目标值小,那就放弃左半边。

本文的所有例题都有分析,题解,并注上详细注释。先自己尝试一下,再看题解哦。

code: #include using namespace std; const int N=1000010; int a[N],x,q,n; int main(){ cin>>n>>q; for(int i=1;i>a[i]; while(q--) { cin>>x; int l=1,r=n; //左右边界 while(l>1; if(a[mid]>=x) r=mid; //判断条件,如果值大于等于目标值,说明在目标值右边,尽量往左来 else l=mid+1; } if(a[l]!=x){ //如果找不到这个值 coutm; for(int i=1;i>a[i]; sort(a+1,a+n+1); //排序勿忘 a[0]=-1e12;a[n+1]=1e12; //最后再解释 while(m--) { cin>>x; int l=1,r=n+1; //r设为n+1 while(l>1; if(a[mid]>=x) r=mid; else l=mid+1; } if(a[l]-x>sum>>t>>mon; double l=0,r=500; //答案范围尽量开大些 while(r-l>1e-5) //精度保证 { double mid=(l+r)/2; if(check(mid)) r=mid; //如果最后还不完了,说明利率高了 else l=mid; } printf("%.1f",l*100); return 0; }

至此,相信你已经对二分查找有一个更加清晰的认识了。

课后再来几个练习题吧: 整数二分: 1、 数的范围 2、 砍树 实数二分: 3、 数的三次方根 4、 一元三次方程求解

学会了二分查找,来学二分答案!

首先:

二分查找与二分答案有何区别?

二分查找:在一个已知的有序数据集上进行二分地查找 二分答案:答案有一个区间,在这个区间中二分,直到找到最优答案

什么是二分答案?

答案属于一个区间,当这个区间很大时,暴力超时。但重要的是——这个区间是对题目中的某个量有单调性的,此时,我们就会二分答案。每一次二分会做一次判断,看是否对应的那个量达到了需要的大小。 判断:根据题意写个check函数,如果满足check,就放弃右半区间(或左半区间),如果不满足,就放弃左半区间(或右半区间)。一直往复,直至到最终的答案。

其实,上面二分查找的例4,寻找的那个区间就是答案区间。

这不就相当于高中做选择题的时候,完了,不会做,那咋搞,把四个选项代进去看看对不对吧!哪个行得通那个就是答案!!

只不过我们现在要找的是最大的或者最小的答案。

如何判断一个题是不是用二分答案做的呢? 1、答案在一个区间内(一般情况下,区间会很大,暴力超时) 2、直接搜索不好搜,但是容易判断一个答案可行不可行 3、该区间对题目具有单调性,即:在区间中的值越大或越小,题目中的某个量对应增加或减少。

此外,可能还会有一个典型的特征:求...最大值的最小 、 求...最小值的最大。 1、求...最大值的最小,我们二分答案(即二分最大值)的时候,判断条件满足后,尽量让答案往前来(即:让r=mid),对应模板1; 2、同样,求...最小值的最大时,我们二分答案(即二分最小值)的时候,判断条件满足后,尽量让答案往后走(即:让l=mid),对应模板2;

先看一个经典的二分答案入门:

例1——木材加工在这里插入图片描述 分析:看,答案就在区间(1,100000000)里,就等着我们找呢,暴力肯定超时,那可能就用二分。 满足条件:

1,答案在一个区间里。 2,如果给一个答案,给目标一个小段的长度,很容易判断是否到K个了。 3,具有单调性,目标小段越长,那能切出的段数越少,目标小段越短,能切出的段数越多。而最终需要K个,从而很容易判断一个答案行不行。

一看求啥,求最长长度,最长?这不,关门打狗,模板2! ! 那,判断条件?模板2,如果满足判断,l=mid。啥叫满足呢?那肯定是满足需要的段数了呗! code: #include using namespace std; const int N=1e5+10; long long a[N],n,m,sum,maxa; int check(int mid) { int sum=0; for(int i=1;i=m) return 1; //总段数大于等于所需要的 return 0; } int main(){ cin>>n>>m; for(int i=1;i>a[i],sum+=a[i]; if(a[i]>maxa) maxa=a[i]; } if(suma[i]; if(a[i]>m; for(int i=1;i>a[i]; if(a[i]>maxa) maxa=a[i]; } sort(a+1,a+n+1); int l=0,r=maxa; while(l>1; if(check(mid)) l=mid; else r=mid-1; } couta[i],summ+=a[i]; if(a[i]maxa) maxa=a[i]; } int l=maxa,r=summ; //l要设为maxa,所有段的最大值肯定大于等于maxa while(l>1; if(check(mid)) r=mid; //求的是最大值的最小,故尽量往左来 else l=mid+1; } cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3