【有营养的算法笔记】整数二分和浮点二分的全面分析

news2025/1/15 12:52:25

👑作者主页:@进击的安度因
🏠学习社区:进击的安度因(个人社区)
📖专栏链接:有营养的算法笔记

文章目录

  • 一、铺垫
  • 二、整数二分模板分析
  • 三、模板应用 —— 数的范围
  • 四、浮点二分模板分析
  • 五、模板应用 —— 数的三次方根

二分算法有时是一个很玄乎的算法,有时稀里糊涂就对了,有时不是死循环就是查找错误。其实就是边界问题处理不当,所以对于二分来说,很有必要有一定的模板,帮助我们快速解决问题。
今天,我们将围绕整数二分和浮点二分进行讲解。

一、铺垫

概念:二分算法,就是在一段 单调且有序 的区间中通过某些条件,不断对二分的起始边界和结束边界进行调整。从而让区间不断压缩,直至找出二分答案,在每次二分后,区间或多或少都会改变。

二分对于我们来说应该是不陌生的。二分查找 大家应该都听说过,这其实就是二分的一层演变拓展,变为更加精确的查找某些值。

概念部分对 单调性 略有提及。其实对于二分算法,区间具有单调性一定可以二分但是二分的题目不一定有单调性

对于二分算法来说,二分是一定会找到答案的。因为二分不断压缩区间,最后必定会分出一个值。

但是这个答案仅仅是对于二分这个算法求出的答案。答案是否正确,还是要结合题目判断。简约的说就是二分的答案不一定是题目的答案,但是二分一定会有答案,无解是对于问题的

有了这些 铺垫 ,我们再看板子。

二、整数二分模板分析

整数二分有两个板子,这也是我觉得最好的板子,简洁,清晰明了。

我们的两个板子二分的最终结果为 边界值

模板1:区间 [l, r] 被划分成 [l, mid][mid + 1, r] 时使用

bool check(double x) {/* ... */} // 检查x是否满足某种性质

int binarySearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}

模板2:区间 [l, r] 被划分成 [l, mid - 1][mid, r] 时使用

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

这里的 check(mid) 函数是为了判断每次二分取的 中间点 mid 是否满足特定性质,从而对区间进行 正确压缩

接下来,我们对两个板子进行分析

模板1

假定一段区间单调递增,区间最左端为 l,区间最右端为 r,区间中点:mid = (l + r) / 2

image-20221209003526121

对于 模板 1二分找的是 蓝色区间的左边界点

mid 可能出现在两个区间中。 check(mid) 检查 mid 是否在 蓝色区间 中。

  1. mid 所在区间为 蓝色区间

此时 check(mid) ,答案在 [l, mid] 区间内。这里取 mid 的原因是查找的是蓝色左端点,mid 在蓝色区间,mid 可能就 是答案 。由于查找的是 左端点 ,所以其他 大于 mid 的情况就 不可能 了。调整 r = mid缩短右边,在左边找答案

  1. mid 所在区间为 红色区间

此时 check(mid) ,答案在 [mid + 1, r] 区间内。这里不取 mid 的原因是查找的是蓝色左端点,mid 在红色区间,所以答案肯定不会落在 mid 上,只有 mid + 1有可能 。调整 l = mid + 1缩短左边,在右边找答案

区间划分情况为 [l, mid][mid + 1, r]

模板 2

假定一段区间单调递增,区间最左端为 l,区间最右端为 r,区间中点:mid = (l + r + 1) / 2(这里为什么这么取中点我们先不关心,马上会讲解)

image-20221209013951407

对于 模板 2二分找的是 红色区间的右边界点

mid 可能出现在两个区间中。check(mid) 检查 mid 是否在 红色区间 中。

  1. mid 所在区间为 红色区间

此时 check(mid) ,答案在 [mid, r] 区间内。mid 在红色区间中,答案 可能取到 mid ,所以区间包含 mid。由于查找的是 右端点,所以小于 mid 的无需考虑。调整 l = mid缩短左边,在右边查找答案

  1. mid 所在区间 蓝色区间

此时 check(mid) ,答案在 [l, mid - 1] 区间内。mid 在蓝色区间中,答案不可能取到 mid,所以区间不包含 mid ,只有 mid - 1有可能 。右边的区间都不需要考虑了。调整 r = mid - 1缩短右边,在左边查找答案

区间划分情况为 [l, mid - 1][mid, r]


讲到这,我们对二分的情况有一些了解后,我们解答一下,为什么 模板 2mid = (l + r + 1) / 2

/ 是下取整的,如果 l = r - 1 ,二分取中点 mid 时,mid = (l + r) / 2 = (l + l + 1) / 2 = l

一旦 check(mid) 满足,那么 l = mid,由于 mid = l,那么 l 就被调整为了 l ,相当于没变,这就 死循环 了。+1 就可以避免掉这种情况。


总结一下 :模板 1 找 区间左边界点,模板 2 找 区间右边界点

image-20221209093441239

例如模板1在上图中找的就是 第一个 3,左端点 ;模板2找的是 最后一个3,右端点

三、模板应用 —— 数的范围

描述

给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。

对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。

如果数组中不存在该元素,则返回 -1 -1

输入格式

第一行包含整数 nq,表示数组长度和询问个数。

第二行包含 n 个整数(均在 1 ∼ 10000 范围内),表示完整数组。

接下来 q 行,每行包含一个整数 k,表示一个询问元素。

输出格式

q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。

如果数组中不存在该元素,则返回 -1 -1

数据范围

1 ≤ n ≤ 100000
1 ≤ q ≤ 10000
1 ≤ k ≤ 10000

输入样例

6 3
1 2 2 3 3 4
3
4
5

输出样例

3 4
5 5
-1 -1

思路

这道题就是模板的经典应用,例如查找的是这样一段区间:

image-20221209093441239

我们查找的是 3 出现的范围,那么返回的就是 3 出现位置的 左端点右端点

这就很简单了,左端点就套用模板1,右端点套用模板2。

需要注意的就是 二分结果是否正确 的判断,以及 check(mid) 的写法。

并且二分结束时,l 是必定等于 r的,所以到时候输出 lr 任意一个即可。

小技巧:如果拿捏不准该使用哪个模板,那么就现根据题意写出 check 后的区间调整状况,根据这个选择模板。

让我们看看代码怎么写:

image-20221209095131989

AC,没问题

四、浮点二分模板分析

相较于整数二分,浮点二分更加简单:

bool check(double x) {/* ... */} // 检查x是否满足某种性质

double binarySearch_3(double l, double r)
{
    const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

浮点二分 不需要 考虑 向上取整向下取整

对于浮点二分来说,调整区间的时候甚至不需要 +1 或 -1。因为是浮点数,+1, -1就可能会错过答案,所以让其等于 mid 自行调整即可。

接下来写道浮点二分题目来练练手。

五、模板应用 —— 数的三次方根

描述

给定一个浮点数 n ,求它的三次方根。

输入格式

共一行,包含一个浮点数 n

输出格式

共一行,包含一个浮点数,表示问题的解。

注意,结果保留 6 位小数。

数据范围:

−10000 ≤ n ≤ 10000

输入样例

1000.00

输出样例

10.000000

思路

数据范围为 [-10000, 10000],所以左右边界 lr 就给定这个范围。

另外需要考虑一下精度问题,题目要求保留 6 位小数,一般我们总结的规律是这样的:精度总是比输出位数多2位,输出6位小数,那么精度就给8位小数。

这里取中的话 (l + r) / 2必须写成 / 的形式,因为是浮点数,无法使用 >> 操作符,不要用错了。

然后再考虑一下 check 函数写法:

  • 如果 mid^3 >= x,说明答案肯定不在右半区间,到左半区间 [l, mid] 找,r = mid
  • 如果 mid^3 < x,说明答案肯定不在左半区间,到右半区间 [mid, r] 找,l = mid

同理,check 函数也可以写成 mid^3 <= x ,处理情况相似,自己推一下就明白了。

让我们看看代码怎么写:

image-20221209102941953

AC,没问题

到这里,本篇博客就到此结束了。一般情况下,二分的题型是都可以使用今天模板解答的。
所以看懂看明白就很重要,一定要多画图推导和多写。
如果觉得anduin写的还不错的话,还请一键三连!如有错误,还请指正!
我是anduin,一名C语言初学者,我们下期见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/74534.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

简单引入JQuery

简单引入JQuery前言环境配置下载官网的JQuery到本机引入JQuery到Html文件中前言 作为一个兢兢业业的后端程序猿&#xff0c;这里为了方便自己搭建的项目更加合理&#xff0c;使自己写的接口对前端也更加友好。所以我决定&#xff0c;从头开始学习下前端知识。 环境配置 下载…

[附源码]JAVA毕业设计翔隆生鲜超市进货管理系统(系统+LW)

[附源码]JAVA毕业设计翔隆生鲜超市进货管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 …

聚宽量化入门量化策略是什么?

聚宽量化入门量化策略JoinQuant聚宽API文档&#xff1a;MetaTradeAPI (metatradeapi) - Gitee.com 获取要操作的股票或指数成分股 1、# 导入函数库&#xff1b; 2、import jqdata&#xff1b; 3、# 初始化函数&#xff0c;设定基准 def initialize(context)&#xff1a; …

每日一题 —— LC. 1687 从仓库到码头运输箱子(难度很大,但值得好好消化的一道题)

1687. 从仓库到码头运输箱子 你有一辆货运卡车&#xff0c;你需要用这一辆车把一些箱子从仓库运送到码头。这辆卡车每次运输有 箱子数目的限制 和 总重量的限制 。 给你一个箱子数组 boxes和三个整数 portsCount, maxBoxes 和 maxWeight &#xff0c;其中 boxes[i][portsi,we…

web前端期末大作业:基于HTML+CSS+JavaScript制作鲜花礼品在线购物网站设计(19页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

代码随想录刷题Day59 | 503. 下一个更大元素 II | 42. 接雨水

代码随想录刷题Day59 | 503. 下一个更大元素 II | 42. 接雨水 503. 下一个更大元素 II 题目&#xff1a; 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的…

云与开源,共植数字世界的根

摘要&#xff1a;本文整理自阿里巴巴集团副总裁、阿里巴巴开源技术委员会负责人贾扬清&#xff0c;在 Flink Forward Asia 2022 主会场的开场致辞。Tips&#xff1a;点击「阅读原文」获取演讲 ppt&#xff5e;云和开源&#xff0c;共生、共长、共植数字世界的根。从在云上使用开…

SAP PS 第17节 项目产成品产出

SAP PS 第17节 项目产成品产出及差异处理1 模拟场景说明1.1 拖拽负库存1.2 发料原材料及报工1.3 执行副产品入库migo发预留1.4 CNS0交货1.5 后面开票产生收入按照项目结算即可项目上有一类比较另类的玩法&#xff0c;就是舍弃PP&#xff0c;依靠网络活动的负库存&#xff0c;实…

Web前端大作业—个人网页(html+css+javascript)我的家乡新密 (15页)含课程设计

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

2030年销售额突破200亿美元!瑞萨电子揭秘智能汽车版图

汽车正在成为继手机之后的下一个智能终端&#xff0c;并且已经成为全球各大芯片头部厂商的必争之地。 过去&#xff0c;汽车芯片市场主要由恩智浦、瑞萨电子、TI等传统汽车芯片巨头垄断&#xff0c;外来者鲜有机会可以入局。但近几年&#xff0c;包括高通、英特尔等全球各大芯…

【无人机】基于Fast行军树(FMT)求解无人机故障路径规划问题附matlab代码和论文

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

ElementPlus弹窗之后让外部区域可编辑

原始的el-dialog弹出以后外部区域是不可编辑的。 为最外层的父元素添加样式 同时给dialog本身添加样式

【工作日推算】JS计算当前时间前N个工作日(去除周末及节假日,文尾附源码下载)

【写在前面】前些日子忙了几天有关指标对比分析的功能&#xff0c;因为系统是对接券商类的业务&#xff0c;所以他们比较关注的是工作日的数据波动&#xff0c;因此前端指标对比数据需要拿工作日的&#xff0c;不然他们停市的数据比较也没用&#xff0c;故而今天针对之前实现的…

如何快速搞懂一家公司?

如果没有快速作为前提&#xff0c;你的搞懂&#xff0c;价值会大打折扣。 一.研究一家公司需要的宏观视野 1.把握长期明确趋势 看清宏观大背景能为你搞懂公司做出铺垫&#xff0c;同时看清这个公司和宏观的密切程度是怎样的&#xff0c;也决定了需要多大程度关注宏观变化。 …

【基于Pycharm的Django3教程】Part1:初识Django

文章目录1 初识Django1.1 django的安装1.2 创建django项目1.3 两种创建方式的对比1.4 默认文件介绍1.5 APP的创建和说明1.6 启动运行django1.7 模板和静态文件1.8 模板语法1.9 请求和响应1.10 orm数据库操作1.11 ORM 数据库案例&#xff1a;用户管理1 初识Django 1.1 django的…

22 条 API 设计的最佳实践

在这个微服务的世界里&#xff0c;后端API的一致性设计是必不可少的。 今天&#xff0c;我们将讨论一些可遵循的最佳实践。我们将保持简短和甜蜜——所以系好安全带&#xff0c;出发咯&#xff01; 首先介绍一些术语 任何API设计都遵循一种叫做“面向资源设计”的原则&#…

TOWER x Binance NFT 桥接教程

TOWER x Binance NFT 销售的 TOWER 门票和人物化身皮肤 NFT 现在可以从 BNB 链桥接到 Polygon 啦&#xff01; 一起来看看如何将你的 TOWER x Binance NFT 从 BNB 链转移到 Polygon&#x1f447; 1、到 BinanceNFT 用户中心提取你的 TOWER NFT 到 BNB Chain&#xff0c;然后等待…

html多个好看的背景动态效果(附源码)

文章目录1.设计来源1.1 图片轮动背景1.2 星空流星背景1.3 动态美女背景1.4 动态屋雨背景1.5 动态街道背景1.6 动态夜幕背景2.效果和源码2.1 动态效果2.2 透明度配置2.2 源代码源码下载作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/arti…

在线绘制富集分析多组气泡图和单细胞分析marker基因矩阵气泡图

常规的GO或者KEGG通路富集分析结果通常以气泡图的形式展示&#xff0c;然而这个气泡图仅仅是一个比较的结果&#xff0c;如果想在一张图上展示多个比较的结果&#xff0c;就需要用到多组气泡图&#xff08;图1&#xff0c;左侧&#xff09;。 单细胞RNA-seq分析结果中&#xf…

delphi异步与javascript

delphi及C Builder异步处理与javascript 目录 delphi及C Builder异步处理与javascript 1、用于实现异步事件、异步方法、及其异步结果回调的可自定义的通用类型 2、你可引用以下基于接口化对象和异步结果的接口的抽象类&#xff0c;去实现异步方法或异步事件的自定义类 2.…