【算法通关指南:算法基础篇】二分算法: 1.A-B 数对 2.烦恼的高考志愿

【算法通关指南:算法基础篇】二分算法: 1.A-B 数对 2.烦恼的高考志愿
在这里插入图片描述
🔥小龙报:个人主页
🎬作者简介:C++研发,嵌入式,机器人等方向学习者
❄️个人专栏:《C语言》《【初阶】数据结构与算法》
永远相信美好的事情即将发生
在这里插入图片描述

文章目录


前言

本文将通过两道经典二分查找例题 ——A-B 数对与烦恼的高考志愿,带你系统掌握二分查找的核心思想与实用技巧。从排序预处理到lower_bound、upper_bound的灵活运用,再到手动实现二分与边界细节处理,由浅入深讲解算法原理与代码实现,帮助你快速攻克二分查找题型,提升编程思维与解题效率

一、A-B 数对

1.1题目

链接:A-B 数对

在这里插入图片描述

1.2 算法原理

由于顺序不影响最终结果,所以可以先把整个数组排序,来研究是佛否有其他的性质。
由A − B = C 得:B = A − C,由于C是已知的数,我们可以从前往后枚举所有的A ,然后去前面找有多少个符合要求的B ,正好可以用二分快速查找出区间的长度。
【STL使用】
1.lower_bound:传入要查询区间的左右迭代器(注意是左闭右开的区间,如果是数组就是左右指针)以及要查询的值k,然后返回该数组中 >= k的第一个位置
2.upper_bound :传入要查询区间的左右迭代器(注意是左闭右开的区间,如果是数组就是左右指针)以及要查询的值k ,然后返回该数组中 > k 的第⼀个位置;

例:a = [10, 20, 20, 20, 30, 40] ,设下标从1 开始计数,在整个数组中查询20 :lower_bound(a + 1, a + 1 + 6, 20) ,返回a + 2 位置的指针;upper_bound(a + 1, a + 1 + 6, 20) ,返回a + 5 位置的指针;

然后两个指针相减,就是包含20 这个数区间的长度。

在这里插入图片描述

1.3代码

#include <iostream>#include <algorithm> using namespace std; typedef long long LL; const int N=2e5+10;LL a[N]; int main(){ int n, c; cin >> n >> c;for(int i =1; i <= n; i++) cin >> a[i];sort(a +1,a +1+ n);LL ret =0;for(int i =2; i <= n; i++){LL b = a[i]- c; ret +=upper_bound(a +1,a + i +1,b)-lower_bound(a +1, a +1+ i, b);} cout << ret << endl;return0;}
注:同时STL的使用范围很「局限」,查询「有序序列」的时候才有用,数组无序的时候就无法使用。但是我们的二分算法也能在「数组无序」的时候使用,只要有「二段性」即可

二、烦恼的高考志愿

2.1 题目

链接:烦恼的高考志愿

在这里插入图片描述

2.2 算法原理

先把学校的录取分数「排序」,然后针对每一个学生成绩 ,在「录取分数」中二分出≥ b的「第一个」位置pos,那么差值最小的结果要么在pos位置,要么在位置pos - 1,那么最后的不满意度求法就为:
abs(a[pos] − b)与abs(a[pos − 1] − b)的最小值。

注:细节问题
如果所有元素都大于b的时候,pos − 1 会在0 下标的位置,有可能结果出错;
• 如果所有元素都小于pos的时候,pos会在n的位置,此时结果倒不会出错,但是我们要想到这个细节问题,这道题不出错不代表下⼀道题不出错。
解决方法:加上两个左右护法,结果就不会出错了

2.3 代码

//烦恼的高考志愿 #include <iostream>#include <algorithm> using namespace std; typedef long long LL; const int N=1e5+10;LL a[N],b[N],m,n;LLfind(LL x){ int l =1, r = m;while(l < r){LL mid =(l + r)/2;if(a[mid]>= x) r = mid;else l = mid +1;}return l;} int main(){ cin >> m >> n;for(int i =1; i <= m; i++) cin >> a[i];//设置左护法 a[0]=-1e7;sort(a +1, a +1+ m);LL ret =0;for(int i =1; i <= n; i++){ cin >> b[i];LL pos =find(b[i]); ret +=min(abs(a[pos -1]- b[i]),abs(a[pos]- b[i]));} cout << ret << endl;return0;}

总结与每日励志

✨通过两道题目,我们学会了利用排序与二分查找快速统计数对、寻找最优匹配,理解了边界处理与 STL 函数的正确使用。二分的本质是寻找二段性,代码简洁却考验思维。愿你在算法学习路上保持耐心与专注,每一次思考都在沉淀成长,永远相信美好的事情即将发生,坚持下去,终会遇见更优秀的自己。

在这里插入图片描述

Read more

【C++笔记】STL详解:vector容器的使用

【C++笔记】STL详解:vector容器的使用

前言:         本文在介绍STL框架基础上,进一步讲解了迭代器、auto关键字和范围for循环的使用方法,接下来我们将重点探讨vector类的常用接口及其应用。          一、vector容器的简介             C++ 的 vector 是标准模板库(STL)中最核心且实用的容器之一,其与固定大小的传统数组(如 int arr[10])不同,vector 克服了数组的局限性,它不需要预先确定大小,并且可以动态调整容量。          简单理解为:vector是可变的、经过封装函数功能的数组。                  核心优势:          ①动态扩容:您不需要一开始就告诉它要存多少数据。当空间不够时,它会在底层自动帮您寻找一块更大的内存,把数据搬过去。          ②内存安全:它负责自己内存的分配和释放,大大减少了手动 new 和 delete 带来的内存泄漏风险。          ③功能丰富:它自带了大量现成的工具函数,比如:获取大小、清空数据、在尾部添加数据等。

By Ne0inhk
C++入门看这一篇就够了——超详细讲解(120000多字详细讲解,涵盖C++大量知识)

C++入门看这一篇就够了——超详细讲解(120000多字详细讲解,涵盖C++大量知识)

目录 一、面向对象的思想 二、类的使用 1.类的构成 2.类的设计 三、对象的基本使用 四、类的构造函数 1.构造函数的作用 2.构造函数的特点 3.默认构造函数 3.1.合成的默认构造函数 3.2.手动定义的默认构造函数 四、自定义的重载构造函数 五、拷贝构造函数 1.手动定义的拷贝构造函数 2.合成的拷贝构造函数 3.什么时候调用拷贝构造函数 六、赋值构造函数 七、析构函数 八、this指针 九、类文件的分离 十、静态数据 1.静态数据成员 2.静态成员函数 十一、

By Ne0inhk
《C++实战项目-高并发内存池》8. 最终性能优化与测试

《C++实战项目-高并发内存池》8. 最终性能优化与测试

💡Yupureki:个人主页 ✨个人专栏:《C++》 《算法》《Linux系统编程》《高并发内存池》 🌸Yupureki🌸的简介: 目录 1. 使用基数树进行优化 2. 性能测试 完整项目链接https://github.com/Yupureki-code/ConcurrentMemoryPool 1. 使用基数树进行优化 现内存池中存在一个比较严重的性能问题:PageCache需要加锁。特别是查找页ID到Span的映射时 因为PageCache中不断存在修改的情况,如果在一个线程查询的过程中,另一个线程同时把这个Span给拿走了,那就出大问题了。同时这把锁直接把整个PageCache给锁住了,因此对锁的竞争会很严重,同时没抢到锁的线程会一直在外面干瞪眼,这造成了严重的性能浪费 因此,Google的大佬们使用了一个新的数据结构:基数树 感兴趣的可以了解:Linux Kernel:内核数据结构之基数树(Radix Tree) - 知乎 基数树,写之前会提前开好空间,写数据过程中,不会动结构。 因为读写是分离的。线程1对一个位置读写的时候,线程2不

By Ne0inhk
C++ 虚函数与纯虚函数:多态的核心实现基石

C++ 虚函数与纯虚函数:多态的核心实现基石

C++ 虚函数与纯虚函数:多态的核心实现基石 💡 学习目标:深度理解虚函数与纯虚函数的本质区别,掌握虚函数表的底层原理,能够灵活运用二者设计具备多态特性的类结构。 💡 学习重点:虚函数的声明与重写规则、纯虚函数与抽象类的使用场景、虚函数表的工作机制、虚函数的常见陷阱与解决方案。 一、虚函数的本质与定义 ✅ 结论:虚函数是 C++ 实现动态多态的核心,通过在基类成员函数前添加 virtual 关键字,允许派生类重写该函数,并在运行时根据对象的实际类型调用对应版本。 1.1 虚函数的声明语法 虚函数的声明必须在基类中进行,语法格式如下: class 基类名 {public:virtual 返回值类型 函数名(参数列表){// 函数体}}; 1.2 虚函数的核心特性 1. 运行时绑定:函数调用关系在程序运行时确定,而非编译时。 2. 重写规则:派生类重写的函数必须与基类虚函数的函数名、参数列表、返回值类型完全一致(协变类型除外)。 3.

By Ne0inhk