蓝桥杯高频考点——二分(含C++源码)

二分

  • 基本框架
  • 整数查找(序列二分的模版题 建议先做)
    • 满分代码及思路
      • solution
  • 子串简写
    • 满分代码及思路
      • solution 1(暴力 模拟双指针70分)
      • solution 2(二分 AC)
  • 管道
    • 满分代码及思路
    • 样例解释与思路分析
      • solution
  • 最大通过数
    • 满分代码及思路
      • solution 1(贪心 50分)
      • 问题
      • solution 2(二分 AC)

基本框架

二分查找的思维确实非常简单 就是引入一个猜炸弹编号的问题 相信大家玩过对吧 假如炸弹是0-100中间的一个数字 不会玩的人可能一个一个猜 会玩的人一般上来就猜50 25 …

二分查找代码中的细节很重要但是真正的坑根本就不是那个细节问题,而是在于到底要给 mid 加一还是减一,while 里到底用 <= 还是 <,

这就要分别对应两种写法 :
一种是左闭右闭区间 一种是左闭右开区间 讲解视频我附在这里:

代码随想录的详细讲解

labuladong 算法笔记 :

在这里插入图片描述

整数查找(序列二分的模版题 建议先做)

在这里插入图片描述
题目链接

满分代码及思路

首先题目其实说的非常直白就是根据给的flag(1 2 3 4 )分别对应四种不同的查询方案 那么我们的main函数就分别对于这四种情况 分别调用函数返回结果即可

做完你再看 序列二分的本质上 是不是 在有限的一个区间或者序列中 快速找到满足条件的数

solution

#include <iostream>
using namespace std;
int n, q;
const int N = 1e5 + 9;
int a[N]; // 存一下序列A
int flag; // 取决于我们该怎么去查找
int l, r, x;
int ans;// 输出 A[l∼r] 中等于 x 最左边的数的下标,若不存在输出 -1
void search1(int l, int r, int x) {ans = -1;while (l <= r) {int mid = l + (r - l) / 2;if (a[mid] == x) {ans = mid;r = mid - 1;} else if (a[mid] < x) {l = mid + 1;} else {r = mid - 1;}}
}// 输出 A[l∼r] 中等于 x 最右边的数的下标,若不存在输出 -1
void search2(int l, int r, int x) {ans = -1;while (l <= r) {int mid = l + (r - l) / 2;if (a[mid] == x) {ans = mid;l = mid + 1;} else if (a[mid] < x) {l = mid + 1;} else {r = mid - 1;}}
}// 输出 A[l∼r] 中大于等于 x 的第一个数的下标,若不存在输出 -1
void search3(int l, int r, int x) {ans = -1;while (l <= r) {int mid = l + (r - l) / 2;if (a[mid] >= x) {ans = mid;r = mid - 1;} else {l = mid + 1;}}
}// 输出 A[l∼r] 中大于 x 的第一个数的下标,若不存在输出 -1
void search4(int l, int r, int x) {ans = -1;while (l <= r) {int mid = l + (r - l) / 2;if (a[mid] > x) {ans = mid;r = mid - 1;} else {l = mid + 1;}}
}int main() {cin >> n >> q;for (int i = 1; i <= n; i++) {cin >> a[i];}while (q--) {cin >> flag >> l >> r >> x;if (flag == 1) {search1(l , r , x);} else if (flag == 2) {search2(l , r , x);} else if (flag == 3) {search3(l , r , x);} else if (flag == 4) {search4(l , r , x);}cout << ans << endl;}return 0;
}    

子串简写

在这里插入图片描述
题目链接

满分代码及思路

solution 1(暴力 模拟双指针70分)

对于这道题目其实我首先想到的就是双指针,具体拿这题来说就是,我们现在有两个指针left right 现在要做的就是 在给定的字符串中枚举出所有同时满足

1.长度大于等于K;
2.以c1开头以c2结尾

以上两个条件的所有子串 对吧
那么就很好办了呀 我们先让left指针找到c1,然后通过不断移动right
枚举出所有以left此时位置为左端点 且满足条件的所有合法情况
每次更新答案count 就好 最后输出一下
但是有几个比较大的样例超时了 这时候我们就需要想办法优化一下:
在这里插入图片描述
因为我们这个双指针的方法 主要依靠两个for循环 时间复杂度是O(n*n)

Q:所以我们要思考的是我们可以去优化的点在哪啊?

也就是说这个代码有什么重复且不必要的操作吗?

我觉得这个思考很重要很重要

A:二分相对于双指针优化的点是不是在于c2位置的确定啊 因为双指针需要枚举right每一种情况吧 因为我们就像一个瞎子 我们的right只有走到它的儿子面前才能跟他相认

具体来说,在双指针方法里,对于每一个以 c1 开头的位置,代码需要从 left + K - 1 开始,逐个枚举所有可能的 right 位置,直到找到以 c2 结尾的位置,从而判断是否满足子串长度大于等于 K 的条件

二分查找方法首先记录下所有 c1 和 c2 出现的位置。对于每一个 c1 出现的位置,要寻找满足子串长度大于等于 K 的 c2 位置时,它利用 c2 位置数组的有序性(因为位置是按顺序记录的)进行二分查找
此时我们的right指针他是一个视力很好的人 他知道自己的子女 在这条路的哪个方位

二分查找每次将搜索范围缩小一半,其时间复杂度为 (O(log m)),其中 m 是 c2 出现的次数。对于所有 c1 出现的位置都进行二分查找,整体时间复杂度就是 (O(n log m)),在一般情况下可以近似看作 (O(n log n)),相比于双指针方法的 (O(n^2)) 有了显著的优化。

#include <iostream>
#include <string>// 引入标准库命名空间
using namespace std;// 双指针方法
int double_point(int K, const string& S, char c1, char c2) {int n = S.length();int count = 0;for (int left = 0; left < n; ++left) {if (S[left] == c1) {for (int right = left + K - 1; right < n; ++right) {if (S[right] == c2) {++count;}}}}return count;
}int main() {int K;string S;char c1, char c2;// 读取输入cin >> K;cin >> S >> c1 >> c2;// 计算结果int result = double_point(K, S, c1, c2);// 输出结果cout << "双指针方法结果: " << result << endl;return 0;
}

solution 2(二分 AC)

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>using namespace std;// 二分查找方法
int binary_search(int K, const string& S, char c1, char c2) {int n = S.length();vector<int> start;vector<int> end;// 记录 c1 和 c2 出现的位置for (int i = 0; i < n; ++i) {if (S[i] == c1) {start.push_back(i);}if (S[i] == c2) {end.push_back(i);}}int count = 0;for (int s : start) {// 二分查找满足条件的 c2 位置int left = 0, right = end.size() - 1;int target = s + K - 1;while (left <= right) {int mid = left + (right - left) / 2;if (end[mid] >= target) {right = mid - 1;} else {left = mid + 1;}}count += end.size() - left;}return count;
}int main() {int K;string S;char c1, c2;// 读取输入cin >> K;cin >> S >> c1 >> c2;// 计算结果int result = binary_search(K, S, c1, c2);// 输出结果cout << "二分查找方法结果: " << result << endl;return 0;
}    

管道

在这里插入图片描述
题目链接

满分代码及思路

代码和思路参考:视频讲解
BZW :这是我偶然刷到的一个up 真的很优秀很有思维

样例解释与思路分析

对于这道题目首先我们需要搞清楚 我们要干嘛
可以将这个管道看成一条线段 阀门就是线段上的点
我们需要明确的是这个阀门只要一打开就会向左右两边同时灌水 就可以看成是以这个点为中心向左右两边延伸 length的长度
并且 len与时间t的函数是一个单调递增函数

在这里插入图片描述

solution

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int n,len;
const int N=1e5+10;
int a[N][2];//存储输入每个阀门的位置和时间
struct door{int L;//位置int S;//时刻
}d[N];
struct line{int l;int r;
}w[N];
//sort比较函数 从小到大排左端点 如果一样就把右端点大的放后面
bool cmp(line A,line B)
{if(A.l!=B.l){return A.l<B.l;}else{return A.r<B.r;}}
bool check(int x)
{int cnt=0;for(int i=0;i<n;i++)//生成区间{if(x<d[i].S)continue;w[cnt].l=d[i].L-(x-d[i].S);w[cnt].r=d[i].L+(x-d[i].S);cnt++;}sort(w,w+cnt,cmp);int last=0;//线段合并for(int i=0;i<cnt;i++){//为什么是last+1 因为题目把这些管道看作是一个个离散的点 所以只要我们新区间的右端点>last+1(l=临界情况)//就return falseif(w[i].l>last+1){return false;}last=max(w[i].r,last);}if(last<len){return false;}return true;
}
int main()
{cin>>n>>len;for(int i=0;i<n;i++){cin>>d[i].L>>d[i].S;}//读入完成int mid=0;int l=0;int r=2e9;//最坏的情况就是从1ee9开始流 直到2e9才能铺满管道//二分答案 左闭右开写法while(l<r){mid=(l+r)/2;if(check(mid))//如果mid这个时间能铺满整个管道 说明在mid右边的时刻都是合法的//那么我们就需要操作://不减1是因为我们不能保证mid是不是临界点 也就是我们不知道mid-1是什么情况{r=mid;}else{l=mid+1;}}cout<<l<<endl;return 0;
}

最大通过数

在这里插入图片描述
题目链接

满分代码及思路

solution 1(贪心 50分)

// 我们现在需要做的就是用这K个水晶 通过尽可能多的关卡 并且我们不需要关心水晶的分配问题
// 也就是说两个人共享一个背包 首先在闯关之前 我肯定想要比较一下左右两个入口 
// 优先通过消耗水晶小的关卡 这样才能保证 最好通过关卡的数量最多
#include <iostream>
using namespace std;
const int N = 2e5 + 9;
int a[N], b[N]; // 分别表示左右两边关卡的能源数量
int n, m, k;    // 初始状态下有n+m道关卡 一共有K个水晶
int passCount;void work() {int i = 0, j = 0;// 先处理左右两边都有的关卡while (i < n && j < m) {if (a[i] <= b[j] && k >= a[i]) {passCount++;k -= a[i];i++;} else if (k >= b[j]) {passCount++;k -= b[j];j++;} else {break;}}// 处理左边剩余的关卡while (i < n && k >= a[i]) {passCount++;k -= a[i];i++;}// 处理右边剩余的关卡while (j < m && k >= b[j]) {passCount++;k -= b[j];j++;}
}int main() {cin >> n >> m >> k;for (int i = 0; i < n; i++) {cin >> a[i];}for (int j = 0; j < m; j++) {cin >> b[j];}work();cout << passCount;return 0;
}

问题

在这里插入图片描述

solution 2(二分 AC)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;const int N = 2e5 + 4;
ll a[N], b[N], pre_a[N], pre_b[N];
ll n, m, k;// 检查是否可以通过 mid 个关卡
bool check(ll mid) {bool ok = false;  // 记录 mid 关卡数是否有可行的方案,不关心 a,b 各通过几关// 从关卡数少的人开始枚举(mid > max(m,n) 时)for (ll i = 0; i <= min(min(m, n), mid); ++i) {// 保证另外一个人有足够的关卡数来凑为 mid 关,没有就跳过if (mid - i > max(m, n)) continue;// 从关卡数少的人开始枚举(保证不越界)if (m <= n && pre_b[i] + pre_a[mid - i] <= k) {ok = true;} else if (n < m && pre_a[i] + pre_b[mid - i] <= k) {ok = true;}}return ok;
}// 解决问题的函数
void solve() {cin >> n >> m >> k;// 读取左边入口每个关卡所需的宝石数for (int i = 1; i <= n; ++i) {cin >> a[i];}// 读取右边入口每个关卡所需的宝石数for (int i = 1; i <= m; ++i) {cin >> b[i];}// 计算 a[i] 前缀和,代表 a 通过 i 关所需的宝石for (int i = 1; i <= n; ++i) {pre_a[i] = pre_a[i - 1] + a[i];}// 计算 b[i] 前缀和,代表 b 通过 i 关所需的宝石for (int i = 1; i <= m; ++i) {pre_b[i] = pre_b[i - 1] + b[i];}// 二分查找最大通过的关卡数ll l = 0, r = m + n + 10;while (l + 1 != r) {ll mid = (l + r) >> 1;if (check(mid)) {l = mid;  // mid 可行,说明 mid 可能可以更大,更新 l} else {r = mid;}}cout << l;  // l 为答案
}int main() {ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;// cin >> t;while (t--) {solve();}return 0;
}

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

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

相关文章

【谷粒商城踩坑记】第五坑 拖拽组件三级菜单拖不了问题

第五坑 拖拽组件三级菜单拖不了问题 直接进入或刷新页面后,拖动第三级菜单项,无法修改排序位置&#xff0c;我尝试了直接用源码包中提供的老师的代码也不行&#xff0c;本身就有这个小 Bug &#xff0c;或者说是其它什么地方有问题。 原始内容是这样的。 countNodeLevel(node){…

《深度剖析Android 12 SystemUI锁屏通知布局亮屏流程:从源码到实现》

优化后文章结构&#xff1a; 1. 前言 强调锁屏通知布局的重要性及分析目的&#xff0c;引出后续源码分析的必要性。 2. 核心类解析 KeyguardViewMediator&#xff1a;锁屏核心逻辑控制&#xff0c;处理亮屏/息屏事件分发。 PhoneWindowManager&#xff1a;系统输入事件&…

Android系统的安全问题 - Android的keymaster和gatekeeper

Android 的 Keymaster 和 Gatekeeper 是两大关键安全组件,分别负责硬件级别的密钥管理和设备解锁认证。它们在 Android 的安全架构中扮演重要角色,尤其在支持 硬件级安全特性(如可信执行环境 TEE 或专用安全芯片)的设备上。以下是它们的详细对比和功能解析: 1. Keymaster(…

springBoot中雪花算术法

在 Spring Boot 中&#xff0c;雪花算法&#xff08;Snowflake Algorithm&#xff09;通常指的是 Twitter 开发的一种分布式唯一 ID 生成算法。它被广泛用于分布式系统中生成全局唯一的 ID&#xff0c;尤其是在高并发场景下。雪花算法生成的 ID 是一个 64 位的长整型数字&#…

鸿蒙开发之ArkTS联合类型

在鸿蒙开发中&#xff0c;ArkTS是一种基于TypeScript的编程语言&#xff0c;专为鸿蒙应用开发而设计。联合类型&#xff08;Union Types&#xff09;在ArkTS中是一个重要的概念&#xff0c;它允许一个变量存储多种类型的数据&#xff0c;从而增加了代码的灵活性&#xff0c;同时…

K8S学习之基础五十五:k8s中jenkins部署blueOcean

jenkins部署blueOcean 安装插件 BLUE OCEAN 之后会多出一个菜单&#xff0c;可以更详细方便的查看pipeline流程

DeepSeek概述

一、DeepSeek概述 1.1 DeepSeek是什么 DeepSeek是一家专注 通用人工智能&#xff08;AGI&#xff0c;Artificial General Intelligence&#xff09;的中国科技公司&#xff0c;主攻大数据研发与应用。DeepSeek-R1是其开源的推理模型&#xff0c;擅长处理复杂任务且可免费商用…

学习记录(14):iOS部署

时隔多年后&#xff0c;再次部署开发iOS&#x1f601;&#x1f601; 1. Unity端设置&#xff0c;在此不再进行赘述&#xff08;网上一大堆&#xff09; 2. ⚠️&#xff1a;要保证mac比待部署的设备版本要高 3. Xcode: (1) 打开从 Unity 3D 里打包的文件中&#xff0c;找到有…

如何使用DeepSeek编写测试用例?

一、DeepSeek在测试用例设计中的定位 DeepSeek作为AI工具,并非直接替代测试设计,而是通过以下方式提升效率: 快速生成基础用例框架(等价类、边界值等) 智能补充易遗漏场景(如特殊字符、异常流) 自动化脚本片段生成(Python/pytest/JUnit等) 测试数据构造建议(符合业务…

9.4分漏洞!Next.js Middleware鉴权绕过漏洞安全风险通告

今日&#xff0c;亚信安全CERT监控到安全社区研究人员发布安全通告&#xff0c;Next.js 存在一个授权绕过漏洞&#xff0c;编号为 CVE-2025-29927。攻击者可能通过发送精心构造的 x-middleware-subrequest 请求头绕过中间件安全控制&#xff0c;从而在未授权的情况下访问受保护…

【前端】原生项目与框架项目区别

不定期更新&#xff0c;建议关注收藏点赞。 使用 HTML CSS JS 和 Vue 或 React 开发的项目各有其优势与不足&#xff0c;适用于不同的场景。目前基本上都采用框架&#xff0c; 总结 何时选择 HTML CSS JS&#xff1a; 适用于 小型项目、简单静态页面、不需要复杂交互 或 …

WinSCP使用教程:(SFTP、SCP、FTP 和 WebDAV)

WinSCP 是一款免费开源的 Windows 环境下的 SFTP、SCP、FTP 和 WebDAV 客户端&#xff0c;主要用于在本地计算机与远程服务器之间安全地传输文件&#xff0c;并提供基本的文件管理功能。 WinSCP是Windows环境下使用SSH的开源图形化的SFTP的客户端 SSH 的全称是 Secure Shell&…

分布式锁实战:Redis与Redisson的深度解析

一、分布式锁的必要性 在分布式系统中&#xff0c;当多个节点需要对共享资源进行读写操作时&#xff0c;传统的本地锁&#xff08;如Java的synchronized或ReentrantLock&#xff09;无法跨节点生效。此时&#xff0c;必须引入分布式锁来保证操作的原子性和一致性。分布式锁需满…

Dify本地安装部署笔记

目录 方式一【docker安装】&#xff1a; 步骤 1&#xff1a;准备工作 步骤2: 克隆dify仓库 步骤3:部署启动dify 步骤 4&#xff1a;访问 Dify 步骤5:升级dify 方式二【源码安装】&#xff1a; 步骤1. 硬件&#xff1a;最低安装要求 步骤2: 业务服务前的3个服务 1. 安…

质检LIMS系统在食品生产加工企业的应用 如何保证食品生产企业的安全

在食品生产加工领域&#xff0c;质量安全是贯穿全产业链的生命线。随着《食品安全法》对全过程追溯要求的深化&#xff0c;传统实验室管理模式已难以满足高效、精准的质量管控需求。质检实验室信息管理系统&#xff08;LIMS&#xff09;作为数字化升级的核心工具&#xff0c;正…

自动驾驶VLA模型技术解析与模型设计

1.前言 2025年被称为“VLA上车元年”&#xff0c;以视觉语言动作模型&#xff08;Vision-Language-Action Model, VLA&#xff09;为核心的技术范式正在重塑智能驾驶行业。VLA不仅融合了视觉语言模型&#xff08;VLM&#xff09;的感知能力和端到端模型的决策能力&#xff0c;…

UDP套接字编程(代码)

什么是socket套接字编程&#xff1f; 通过Ip地址 端口号这种方式定位一台主机&#xff0c;这样的方式我们就叫做socket套接字。 Udp Socket 接口介绍 这些案列我们使用的接口基本都是一样的&#xff0c;所以在这里我先把接口介绍完&#xff0c;具体的细节后面在说明。 创…

汽车行业可信数据空间研究探索

近期&#xff0c;相关老师在新能源汽车国家大数据联盟微课堂发表了题为“汽车行业可信数据空间研究探索”的演讲&#xff0c;主要包括可信数据空间的概念内涵、汽车行业可信数据空间的发展现状、数据流通场景和技术需求研究、汽车行业可信数据空间的场景建设建议四个方面展开。…

圆弧插补相关算法汇总(C++和ST源代码)

运动控制需要了解相关的插补概念,在阅读本篇博客之前需要了解相关的准备知识,常用链接如下: SMART PLC直线插补详解-CSDN博客文章浏览阅读2.1k次,点赞2次,收藏4次。本文介绍了SMART PLC中轴组对象的概念,详细讲解了直线插补的原理和指令使用,包括SMART PLC从V2.7版本开…

Entity Framework框架

深入理解C#中的Entity Framework框架&#xff1a;从理论到实践 在C#开发中&#xff0c;与数据库交互是几乎所有应用程序的核心需求之一。Entity Framework (EF) 作为微软官方推出的ORM框架&#xff0c;极大地简化了数据库操作。本文将带您深入理解EF框架的核心概念&#xff0c…