【C++例题 / 训练】二分算法(模板 例题)

引言

二分也就是二分查找,又叫折半查找。这种算法正如其名,每一次都要分一半。

二分算法可以分为二分查找和二分答案。

以在一个升序数组中查找一个数为例,每次考察数组当前部分的中间元素,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,那么左侧的只会更小,不会有所查找的元素,只需到右侧查找;如果中间元素大于所查找的值同理,只需到左侧查找 

二分法的使用条件

二分法是适用于解决具有“二段性”(单调性)的问题的方法,通常表现为求解满足某一条件的最大值或者最小值

  1. 上下界确定。 我们可以通过上下界的折半来优化查找。
  2. 二段性: 对某一范围内的数据,存在一个临界点,使得临界点某一侧的所有数据都满足某一性质,另一侧的所有数据都不满足这一性质,就称这一范围内的数据具有二段性。

二段性包括单调性,即区间内有序,这样二分出来的结果是严格大于或者小于或等于target的。
但是,二段性也体现在非单调性上,也称为局部有序,可以参考 162. 寻找峰值 和 33. 搜索旋转排序数组。由这些题我们可以得知,二分法的奥义(本质)不在于单调性,而是二段性。也就是我们能对整体无序但局部有序的序列进行二分法。

二分的前提条件

1、答案在一个区间内(一般情况下,区间会很大,暴力超时)

2、直接搜索不好搜,但是容易判断一个答案可行不可行

3、该区间对题目具有单调性,即:在区间中的值越大或越小,题目中的某个量对应增加或减少。

4、若有多个答案满足题意,则这些答案具有如下特点:若答案 x 满足,则答案范围内小于 x 或大于 x 的答案均满足。

模板

🥑1 朴素版

while (l <= r)
{int mid = (r - l) / 2 + l;  //防止溢出,和mid = (r - l + 1) / 2 + l;等价if (...) l = mid + 1;else if (...) r = mid - 1;else return ...;
}

🍉2 求大于等于目标的最小值(查找区间左端点)

while (l < r) //区间不为空
{int mid = ((r - l) >> 1) + l;if (...) l = mid + 1;  else r = mid;
}

🥝3 求小于等于目标的最大值(查找区间右端点)

while (l < r)
{// 当l,r相邻时,会l=mid,<r,死循环,模板1不影响,因为l=mid+1=r int mid = ((r - l + 1) >> 1) + l;if (...) l = mid;else r = mid - 1;

例题

1. 二分查找

class Solution {
public:int search(vector<int>& nums, int target) {int l = 0, r = nums.size() - 1;while (l <= r){//int mid = (r - l) / 2 + l; //朴素版本下 两个都行int mid = (r - l + 1) / 2 + l;if (nums[mid] == target) return mid;else if (nums[mid] > target) r = mid - 1;else l = mid + 1;}return -1;}
};

2.  在排序数组中查找元素的第一个和最后一个位置

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {if (nums.size() == 0) return { -1,-1 };int begin = 0;// 1. 二分左端点int l = 0, r = nums.size() - 1;while (l < r) //区间不为空{int mid = ((r - l) >> 1) + l;if (nums[mid] < target)l = mid + 1;else r = mid;}// 判断是否有结果if (nums[l] != target) return { -1,-1 };else begin = l; //标记左端点l = 0, r = nums.size() - 1;while (l < r) //区间不为空{int mid = ((r - l + 1) >> 1) + l;if (nums[mid] > target) r = mid - 1;else l = mid;}return { begin, r};}
};


3. x 的平方根 

class Solution {
public:int mySqrt(int x) {if (x < 1) return 0;int l = 1, r = x;while (l < r) //精度保证{long long mid = (r - l + 1) / 2 + l; //防止溢出if (mid * mid <= x) l = mid;else r = mid - 1;}return l;}
};

4. 搜索插入位置

class Solution {
public:int searchInsert(vector<int>& nums, int target) {int l = 0, r = nums.size();while (l < r){int mid = (r - l) / 2 + l;if (nums[mid] < target) l = mid + 1;else r = mid;}return l;}
};

5. 山脉数组的峰顶索引

思路:

 该题仍具有二段性,左边递增,右边递减,用二分查找算法,

当前山峰高于左边山峰,区间往右缩小,否则往左缩小

注:封顶的左边区间,一定是递增的,因此套用模板三即可,找最右端点

class Solution {
public:int peakIndexInMountainArray(vector<int>& arr) {int l = 1, r = arr.size() - 2;while (l < r){int mid = l + (r - l + 1) / 2;if (arr[mid] > arr[mid - 1]) l = mid;else r = mid - 1;}return r;}
};

6、寻找峰值

思路:

该题相比于上题,该题有多个峰值存在,故在两个封顶之间的区间内,从左到右一定递增,故套用模板二,找区间左端点即可。

class Solution {
public:int findPeakElement(vector<int>& nums) {int l = 0, r = nums.size() - 1;while (l < r) // 左边如果不大于右边,则{int mid = (r - l) / 2 + l;if (nums[mid] > nums[mid + 1]) r = mid ; else l = mid + 1;}return l;}
};

7. 寻找旋转排序数组中的最小值

思路:

class Solution {
public:int findMin(vector<int>& nums) {int l = 0, r = nums.size() - 1;int x = nums[r];while (l < r){int mid = (r - l) / 2 + l;if (nums[mid] <= x) r = mid;else l = mid + 1;}return nums[l];}
};

8. 点名

思路:

按照缺失的数分为左右两个区间。

左边,nums[i] == i (left = i + 1)

右边 nums[i]  > i. (right = i)

注:当缺失的数是最后一个数,需要做下特殊判断,因此r 从 n 开始

class Solution {
public:int takeAttendance(vector<int>& records) {int l = 0, r = records.size();while (l < r){int mid = (r - l) / 2 + l;if (records[mid] == mid) l = mid + 1;else r = mid;}return l;}
};

9. A-B 数对

思路:

这里使用库函数二分的写法:

依次枚举 A ,将问题转变成统计数列中 B + C 出现了多少次。先对数列排序,那么 B + C 会对应这个数列的连续一段,只要找到这个连续段的左端点和右端点即可。(需使用头文件 algorithm)

  1. lower_bound(begin, end, val)在区间 [begin, end)中找到val第一次出现位置;
  2. upper_bound(begin, end, val)在区间 [begin, end)中找到val最后一次出现位置的后面一位 

则这个数出现的次数就可以表示为 upper_bound() - lower_bound(),时间复杂度为 O(nlogn).

#include <iostream>
#include <algorithm>
using namespace std;const int N = 2e5 + 10;
int a[N];int main()
{int n, c;cin >> n >> c;for (int i = 0; i < n; i++) cin >> a[i];sort(a, a + n);int tot = 0;for (int i = 0; i < n; i++)tot += upper_bound(a, a + n, a[i] + c) - lower_bound(a, a + n, a[i] + c);cout << tot << endl;return 0;
}

10. 进击的奶牛

思路:

先构造判断 “条件”:可以把 c 头牛全部安置进这些隔间使相邻两头牛距离不超过 x 。x 越小,就越可能把所有牛合法安置;当 x 比较大时,牛棚就不够安置了。于是,存在一个分界线 ans,当 x 大于 ans 时就没有合法的安置方案,当 x 小于或等于 ans 时,则一定存在一个合法的安置方案。

可以得到,在合法的答案中,任意两个相邻安置点都不能小于 x 。那么只需要遍历所有点,从最左端开始,每隔超过 x 的距离,能安置则安置,最后判断能否全部安置完。若不能,则缩小 x ,重复上述遍历过程。

#include <iostream>
#include <algorithm>
using namespace std;int a[100005], n, m;//注意:这是拿出来的那些里,mid为最短距离,和跳石头不同的是,跳石头是在留下的里面,mid为最短距离 
bool check(int mid)
{int now = 0, cnt = 0;for (int i = 1; i < n; i++){if (a[i] - a[now] >= mid)  //计算有几个隔间距离大于midcnt++, now = i;}return cnt + 1 >= m; //  + 1,是因为需要算上 a[1],//如果拿出的总个数大于等于m,都能保证拿走的瓶盖间距大于等于mid,那拿出来m个,肯定也能满足!!
}int main()
{cin >> n >> m;for (int i = 0; i < n; i++) cin >> a[i];sort(a, a + n); //排序隔间int l = 1, r = a[n - 1] - a[0]; // 距离大于1 while (l < r)//找右端点{int mid = (r - l + 1) / 2 + l;if (check(mid)) l = mid;else r = mid - 1;  }cout << l << endl;return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java MessagePack序列化工具(适配Unity)

Java MessagePack序列化工具&#xff08;适配Unity&#xff09; 前言项目代码编写 结 前言 前后端统一用MessagePack&#xff0c;结果序列化的结果不一样&#xff0c;发现C#侧需要给每个类增加描述字段数量的Head&#xff0c;而Java却不用&#xff0c;所以在Java侧封装一下序列…

运行微信小程序报错:Bad attr data-event-opts with message

问题 使用uniapp 编译&#xff0c;运行微信小程序环境时&#xff0c;报错 Bad attr data-event-opts with message。&#xff08;这个错误报错原因很多&#xff0c;这里只解决一个&#xff09; 原因 原因是&#xff1a;代码中有&#xff1a; :key"swiperList i"…

近年国际重大网络安全事件深度剖析:安全之路任重道远

引言 在当今数字化时代&#xff0c;网络安全已成为全球关注的焦点。随着信息技术的飞速发展&#xff0c;网络攻击的手段和规模也在不断升级&#xff0c;给个人、企业和国家带来了巨大的威胁。本文将盘点近年来国际上发生的重大网络安全事件&#xff0c;分析其影响和教训&#…

虚幻引擎游戏开发 | 程序化生成道具位置 Randomize Height

当地图上有无数个收集物【如水晶】&#xff0c;一键随机化高度 应用前 应用后 这时候水晶的高度是离散型地在0和110两个数中平均概率地选择。 如果要有权重地分布高度&#xff0c;减少高位水晶的比例&#xff08;由于过多连续跳跃会让玩家无聊和难以持续专注&#xff09;可以加…

什么是制造业项目管理软件?适合制造企业的项目管理软件具备哪些特征

当前&#xff0c;我国的制造业呈现出稳步增长与风险并存的现象。经济构建以国内大循环为主体&#xff0c;国产替代的浪潮正在席卷国内制造业&#xff0c;越来越多的制造领域企业开始启动数字化变革来支撑企业的迅猛发展&#xff0c;进一步优化项目管理流程&#xff0c;促进研发…

深入理解HTTP的基础知识:请求-响应过程解析

首先&#xff0c;我们从网络协议的最顶层开始讲解&#xff0c;即应用层。在网络通信中&#xff0c;应用层是最接近用户的一层&#xff0c;它负责为特定的网络应用提供服务和功能。应用层协议定义了数据交换的规则和格式&#xff0c;以便不同的应用程序能够相互通信和交换信息。…

[数据集][目标检测]航拍屋顶检测数据集VOC+YOLO格式458张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;458 标注数量(xml文件个数)&#xff1a;458 标注数量(txt文件个数)&#xff1a;458 标注类别…

03 C语言实现单向循环链表

#include "stdio.h" #include "stdlib.h"typedef int datatype_t;typedef struct node {datatype_t data;struct node *next; } looplist_t;// 单向循环链表创建 looplist_t *looplist_create() {looplist_t *head (looplist_t *) malloc(sizeof(looplist…

【Orb-Slam3学习】 ORBextractor类主要成员函数调用关系

简介 主要是介绍一下ORBextractor类的函数简要流程以及调用关系。 构造函数 ORBextractor::ORBextractor 主要作用是初始化一下ORBextractor类的成员函数 列表初始化部分&#xff1a; nfeatures(_nfeatures), scaleFactor(_scaleFactor), nlevels(_nlevels), iniThFAST(_in…

Ansys Zemax|如何自定义优化操作数

虽然Zemax OpticStudio有300多个内建优化操作数&#xff0c;但是还是会有一些特殊情况是这300多个操作数无法涵盖的。这就要求使用者根据要求计算出某些特定的数值&#xff0c;将这些数值返回到某个操作数&#xff0c;再对此操作数进行优化。 Zemax OpticStudio支持用户编程&a…

plsql表格怎么显示中文 plsql如何导入表格数据

在Oracle数据库开发中&#xff0c;PL/SQL Developer是一款广泛使用的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它提供了丰富的功能来帮助开发人员高效地进行数据库开发和管理。在使用PL/SQL Developer时&#xff0c;许多用户会遇到表格显示中文的问题&#xff0c;以…

针孔相机模型(Pinhole Camera Model)详解:三维世界到二维图像的映射

针孔相机模型&#xff08;Pinhole Camera Model&#xff09;详解&#xff1a;三维世界到二维图像的映射 针孔相机模型&#xff08;Pinhole Camera Model&#xff09;是计算机视觉和计算机图形学中的一个基础且重要的概念&#xff0c;它描述了三维空间中的点与它们在理想针孔相…

C/C++控制台贪吃蛇游戏的实现

&#x1f680;欢迎互三&#x1f449;&#xff1a;程序猿方梓燚 &#x1f48e;&#x1f48e; &#x1f680;关注博主&#xff0c;后期持续更新系列文章 &#x1f680;如果有错误感谢请大家批评指出&#xff0c;及时修改 &#x1f680;感谢大家点赞&#x1f44d;收藏⭐评论✍ 一、…

【Ansible】Ansible playbook

Ansible playbook简介 Ansible playbook是一种用于描述和自动化IT基础设施配置和管理的工具。它使用YAML格式来定义一系列任务和配置项&#xff0c;并利用Ansible的执行引擎自动执行这些任务。 Playbook包含一个或多个play&#xff0c;每个play定义了一组任务&#xff0c;这些…

基于STM32开发的智能家居安防系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化传感器数据采集与处理安防控制与报警机制Wi-Fi通信与远程监控应用场景 家庭安防系统办公室与商铺的安全监控常见问题及解决方案 常见问题解决方案结论 1. 引言 随着智能家居技术的…

WPF 动画 插值动画、关键帧动画、路径动画

WPF动画&#xff0c;分为三种&#xff1a;插值动画、关键帧动画、路径动画 2.1 插值动画&#xff1a;     1&#xff09;定义&#xff1a;插值动画是指&#xff0c;属性值从某一个值&#xff0c;经过一段时间后&#xff0c;连续变化值另一个值的动画。         例…

Nginx服务器申请及配置免费SSL证书

免费SSL证书申请 背景&#xff1a; 我的情况是这样&#xff0c;域名解析是华为云的&#xff0c;然后免费证书在腾讯云申请。但是大致的配置流程都是一样的 在腾讯云平台申请免费的SSL证明(目前有效期是90天)&#xff0c;申请步骤如下 主要步骤说明 申请免费SSL证书根据申请时说…

一码当鲜-001 这段代码是做什么?

一码当鲜 你能看出来吗&#xff1f; 1. 分页支持 2. RBC 权限申明 源自 ApiHug - API Design & Develop New Paradigm.ApiHug - API Design & Develop New Paradigm.https://apihug.com/

vue一键打不同环境的包

1.配置package.json 主要看的是 "build:all": "vue-cli-service build && vue-cli-service build --mode test && vue-cli-service build --mode development", "scripts": {"dev": "vue-cli-service serve"…

共享电动单车管理系统 ---附源码131016

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于共享电动单车管理系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了共享电动单车管理系统&#xff0c;它彻底…