第二章:整数二分与浮点数二分(极限思想)_浮点数二分为什么不加一-程序员宅基地

技术标签: 算法  c++  二分  算法合集(c++实现)  

二分的数学思想:

二分的数学思想其实就是极限,我们通过取中点的方式,不断地缩小答案所在的区间,让这个区间不断地逼近答案,类似于我们在高数中所学的极限:
在这里插入图片描述

一、整数二分

1、思路

在这里插入图片描述

我们假设想要寻找上述数轴中的左右边界。

我们先看左边界中的A点,不看B点。我们仔细观察一下A点处符合的性质。

在这里插入图片描述
根据上图中的性质,我们就可以开始写二分了。

根据刚刚的描述二分是一个不断逼近地过程,可以理解为两侧端点不断靠近的过程。

将左端点的下标设为 l l l,右端点下标设为 r r r,中间点的下标设为 m i d mid mid m i d = ( l + r ) / 2 mid = (l+r)/2 mid=(l+r)/2

l = 0 l=0 l=0, r = n − 1 r=n-1 r=n1

如果 m i d mid mid处所对的元素值小于 4 4 4,说明我们的端点 A A A一定不在 m i d mid mid点处,又因为这个序列是单调递增的,所以 m i d mid mid左侧的数字都是小于 m i d mid mid所对的值的。也就是说 m i d mid mid左侧的数字都是小于 4 4 4的,而我们的 A A A处是等于 4 4 4的。

那么知道这个有什么用呢?

这就说明 m i d mid mid的左侧包括 m i d mid mid都不可能是 A A A点,所以我们可以让 l = m i d + 1 l = mid + 1 l=mid+1

如果 m i d mid mid处所对的值是大于等于 4 4 4的,说明 m i d mid mid右侧的值也一定是大于等于 4 4 4的。

m i d mid mid处的值也是等于 4 4 4的,也就是说 m i d mid mid处可能是答案,此时我们考虑一下 m i d mid mid右侧的情况。

如果 m i d mid mid右侧的值都比 m i d mid mid大,那么 m i d mid mid右侧的树也不可能是答案,因为他们都大于 4 4 4

如果 m i d mid mid右侧还有等于 4 4 4的值,但这些不可能是答案,因为我们找的是区间的左端点,如果 m i d mid mid处是 4 4 4,那么 m i d mid mid右侧的 4 4 4肯定不是左端点。

通过上面对 m i d mid mid右侧的讨论,我们发现 m i d mid mid右侧都不可能是答案,但是 m i d mid mid处有可能是答案。所以我们可以扔掉 m i d mid mid右侧的数,即直接让 r = m i d r = mid r=mid

通过一轮的比较,我们发现两端的端点再向中间靠拢。

因此我们只需要重复上面的比较,当左端点和右端点合并到一起的时候,那个点就是区间的左端点 A A A

接着我们考虑区间的右端点。

在这里插入图片描述

右端点就是 B B B点,还是和刚才的思路一样,B点一定在这个数轴上,所以我们让左端点 l l l指向起点 0 0 0,右端点 r r r指向最后一个元素下标的 n − 1 n-1 n1

我们求出一个中点 m i d mid mid

如果 m i d mid mid处所对的值是大于4的。

那么 m i d mid mid处肯定不符合条件,由于这个序列是单调递增的,所以 m i d mid mid右侧的数字也一定是大于4的,即不符合条件的。因此,我们可以直接扔掉 m i d mid mid所对的点和它右面的点。即 r = m i d − 1 r = mid - 1 r=mid1

接着如果 m i d mid mid处所对的值是小于等于4的。

那么 m i d mid mid处有可能是答案,然后我们考虑 m i d mid mid左侧的值。

如果 m i d mid mid左侧的值都是小于4的,那么 m i d mid mid左侧的数字肯定不是答案,可以直接扔掉,如果 m i d mid mid左侧存在等于4的数,这些4也不可能是答案,因为我们找的是右端点,mid在这些4的右面。所以也可以扔掉。

因此如果 m i d mid mid处所对的值,我们可以直接扔掉 m i d mid mid左侧的数,但是需要保留 m i d mid mid,即 l = m i d l=mid l=mid

但是我们找左端点的时候, m i d = ( l + r ) / 2 mid=(l+r)/2 mid=(l+r)/2,而现在由于除法是下取整,所以mid的算法是 ( l + r + 1 ) / 2 (l+r+1)/2 (l+r+1)/2

为什么呢?

我们看下面这个极端的例子:
在这里插入图片描述

2、模板

我们以下面的题目为例:

在这里插入图片描述

上述题目来自acwing网站

C++版

#include<iostream>
using namespace std;
const int N=1e6+10;
int arr[N];

int main()
{
    
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++)scanf("%d",&arr[i]);
    while(m--)
    {
    
        //输入要查找的数字
        int f=0;
        cin>>f;
        //开始二分:
        //寻找左边界
        int l=0,r=n-1;
        int mid;
        while(l<r)
        {
    
            mid=(l+r)>>1;
            if(arr[mid]>=f)r=mid;
            else l=mid+1;
            
        }
        if(arr[l]!=f)cout<<"-1 -1"<<endl;
        else
        {
    
            cout<<l<<" ";
            //寻找右边界
            l=0,r=n-1;
           
            while(l<r)
            {
    

                mid=(l+r+1)>>1;
                if(arr[mid]<=f)l=mid;
                else r=mid-1;
            }
            cout<<r<<endl;
        }
    }
    
    return 0;
}

二、浮点数二分

1、思路:

假设我们想求一个数字的立方根,并且要保留6位小数,那么必定存在一个范围都是满足这个答案的,因为通过四舍五入后,这个范围的答案都是正确的。此时我们就可以利用浮点数二分。
在这里插入图片描述
所以浮点数二分的思想就是,我们让l到r所组成的区间全部落在答案所在的范围内。此时我们在输出答案即可。
在这里插入图片描述
来自acwing

2、代码:

C++版

#include<iostream>
using namespace std;

double x;
double l=-10000.00;
double r=10000.00;
int main()
{
    
    cin>>x;
    while(r-l>1e-10)
    {
    
        double mid=(r+l)/2;
        if(mid*mid*mid>=x)r=mid;
        else l=mid;
    }
    printf("%.6lf",l);;
    return 0;
}

C

#include<stdio.h>

double x;
double l=-10000.00;
double r=10000.00;
int main()
{
    
    scanf("%lf",&x);
    while(r-l>1e-10)
    {
    
        double mid=(r+l)/2;
        if(mid*mid*mid>=x)r=mid;
        else l=mid;
    }
    printf("%.6lf",l);;
    return 0;
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_72060925/article/details/127835264

智能推荐

TortoiseGit小乌龟工具上传解析-程序员宅基地

文章浏览阅读5.2k次。使用tortoiseGit工具一直出错,由于没有设置自动获取putty key这一项,从网上找了一个教程,现分享如下,以做参考:前半部分参考网上的例子:http://www.showerlee.com/archives/1300,但会出现“git did not exit cleanly (exit code 128)”错误1.在D盘新建一个目录,例如"D:\Git",并进入目录右键目录空白处选择...

bindgetuserinfo="onGotUserInfo" and @getuserinfo="onGotUserInfo_component "pages/index/index" does not have a meth-程序员宅基地

文章浏览阅读1.9k次。发现使用uni-app获取UserInfo,结果使用微信官网栗子发现只弹出提示,没获取到值如下<button open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="onGotUserInfo">获取用户信息</button>onGotUserInfo: function (e) { console.log(e) ..._component "pages/index/index" does not have a method "getuserinfo" to handle

Java实现以太坊空投工具_java nft空投-程序员宅基地

文章浏览阅读1k次。以太坊空投工具实现代码展示public class AirDropContract { // TODO: 节点URL private final static Web3j web3j = Web3j.build(new HttpService("")); // TODO: 代币合约地址 public static final String coinAddress = ""; // TODO: 部署合约地址 public static final Strin_java nft空投

Java+SSM+Vue劳务外包管理系统源码+论文-程序员宅基地

文章浏览阅读125次。系统可以提供信息显示和相应服务,本系统管理员管理用工单位,派遣员工,合同,黑名单,招聘信息,客户信息,统计员工在职信息与客户开发信息。业务员查看客户开发统计信息,查询供应商与客户。员工可以查询合同,档案,异动以及黑名单信息。开发软件:Eclipse、MyEclipse、IDEA都可以运行。后端:Java+SSM框架。

jquery设置元素的显示、隐藏_jquery 隐藏-程序员宅基地

文章浏览阅读6.1k次,点赞2次,收藏7次。(“#id”).show()表示为display:block;$(“#id”).hide()表示为display:none;$(“#id”).toggle()切换元素的可见状态。如果元素是可见的,切换为隐藏的;如果元素是隐藏的,则切换为可见的。_jquery 隐藏

python idle怎么打开_注册表编辑器怎么打开-程序员宅基地

文章浏览阅读314次。注册表编辑器怎么打开注册表编辑器在电脑运用中使用非常广泛,每个软件的安装都有注册表的生成,所以通过修改注册表还可以设置软件参数等,解决一般电脑软件所无法解决的设置问题。那么注册表编辑器怎么打开呢?很多新手朋友相信都还不知道,下面编辑介绍在windows xp系统下与win 7系统下注册表编辑器怎么打开的方法。windows xp系统下打开注册表编辑器方法方法一:在我的电脑桌面 开始 - 运行 在运..._python如何打开regedit

随便推点

详解NTFS文件系统_ntfs文件系统中,磁盘上的所有数据包括源文件都是以什么的形式存储-程序员宅基地

文章浏览阅读5.7k次,点赞4次,收藏13次。上篇在详解FAT32文件系统中介绍了FAT32文件系统存储数据的原理,这篇就来介绍下NTFS文件系统。NTFS、用过Windows系统的人都知道,它是一个很强大的文件系统,支持的功能很多,存储的原理也很复杂。目前绝大多数Windows用户都是使用NTFS文件系统,它主要以安全性和稳定性而闻名,下面是它的一些主要特点。安全性高:NTFS支持基于文件或目录的ACL,并且支持加密文件系统(E_ntfs文件系统中,磁盘上的所有数据包括源文件都是以什么的形式存储

【深度学习】【目标检测】损失函数smooth L1 Loss_smooth_l1_loss公式-程序员宅基地

文章浏览阅读1.2k次。pytorch之常用Loss函数总结参考文档L1、L2、smooth L1 Losssoftmax_cross_entropy_with_logitssparse_softmax_cross_entropy_with_logitsbinary_cross_entropysigmoid_cross_entropy参考文档参考文档参考文档L1、L2、smooth L1 Losssoftmax..._smooth_l1_loss公式

PAT 乙级 1017 (方法 + 代码)_pat 1017乙-程序员宅基地

文章浏览阅读462次。1017 A除以B (20 分)本题要求计算 A/B,其中 A 是不超过 1000 位的正整数,B 是 1 位正整数。你需要输出商数 Q 和余数 R,使得 A=B×Q+R 成立。输入格式:输入在一行中依次给出 A 和 B,中间以 1 空格分隔。输出格式:在一行中依次输出 Q 和 R,中间以 1 空格分隔。输入样例:123456789050987654321 7输出样例:17636..._pat 1017乙

P3566 [POI2014] KLO-Bricks 题解-程序员宅基地

文章浏览阅读244次。现在有n种颜色的砖块,第一个必须放第p种颜色,最后一定得放第q种颜色,剩余中间的需要自己构造,使得每相邻两个砖块的颜色不相等,有解随便输出任意一种,无解则输出0。

oracle lob 并行,ORACLE LOB大对象处理-程序员宅基地

文章浏览阅读100次。主要是用来存储大量数据的数据库字段,最大可以存储4G字节的非结构化数据。主要介绍字符类型和二进制文件类型LOB数据的存储,单独介绍二进制类型LOB数据的存储。一,Oracle中的LOB数据类型分类1,按存储数据的类型分:①字符类型:CLOB:存储大量 单字节 字符数据。NLOB:存储定宽 多字节 字符数据。②二进制类型:BLOB:存储较大无结构的二进制数据。③二进制文件类型:BFILE:将二进制文..._oracle 多个lob中文件合并

Ruby语言基础知识-程序员宅基地

文章浏览阅读1.5k次。Ruby是一种简单快捷的面向对象脚本语言,由日本人松本行弘(Yukihiro Matsumoto)在20世纪90年代开发,遵守GPL协议和Ruby License。它的灵感和特性来自于Perl、Smalltalk、Eiffel、Ada以及Lisp语言。以下是Ruby语言的一些特点:面向对象:在Ruby中,一切皆是对象。这意味着所有的数据和代码都被视为对象,每个对象都有自己的属性和方法。动态类型:Ruby是一种动态类型语言,这意味着你不需要在声明变量时指定其类型。_ruby语言

推荐文章

热门文章

相关标签