[数据结构与算法基础] XXX目录
1 STL知识点
STL,即标准模板库(Standard Template Library),是C++标准库中的一个重要组成部分。它提供了一组通用的类和函数模板,用于处理数据结构和算法。STL的主要目标是提高程序的可重用性、效率和可维护性。
说白了就是一个库,而我们常常会使用其中的一些容器,快速实现需求。常用容器概述如下:
- vector 变长数组,使用了倍增的思想
- pair ,常用
- string 字符串,字符串取子串的函数常用,substr() , c_str()
- queue, priority_queue 队列
- queue 常用操作push(),front(),pop()
- priority_queue 优先队列,实际上就是堆,常用push(),top(),pop()
- stack 栈,常用push(),top(),pop()
- deque 双端队列,队头队尾都可以插入删除,而且可以随机访问, 是加强版的vector
- set,map,multiset,multimap
- set与mat,基于平衡二叉树(红黑树)实现,红黑树是平衡二叉树的一种,动态维护有序序列
- unordered_set, unordered_map,unordered_multiset,unordered_multimap,基于哈希表实现
- bitset 压位,用于状态压缩
2 练习题
本文首先提供一些基础的练习题,方便了解STL的使用,以及常使用于什么类型的练习题中。
2.1 洛谷题单P3879
题目信息:
思路:
使用STL解决此题,可以使用map,构造出map<string,set>
完整代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
using namespace std;
const int N = 100010;
int n, m, num;
string s;
map<string, set<int>> a;
int main()
{
std::ios::sync_with_stdio(false); // 要关闭同步,快很多 // when we should use it?
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> num;
for (int j = 1; j <= num; j++)
{
cin >> s;
a[s].insert(i); // 将单词与序号 i 关联
}
}
cin >> m;
for (int i = 1; i <= m; i++)
{
cin >> s;
if (a.find(s) != a.end()) // 如果关键词 s 存在于 map 中,则输出关联的序号集合
{
for (const auto &elem : a[s])
{
cout << elem << " ";
}
}
cout << endl;
}
return 0;
}
知识点:
-
map查找操作
-
if(a.find()!=a.end())
find()
函数查找失败时会返回end()
,据此这样写
-
-
map遍历
for (auto it = a.begin(); it != a.end(); ++it) { // 处理每个元素 }
-
set遍历操作
for (const auto &elem : a[s]) { cout << elem << " "; }
2.2 洛谷题单P1059
题目信息:
思路:
此题可以衔接上一题的思路
- 去重⇒使用set
- 排序⇒使用vector或者普通数组,我采用了数组,因为list效率更高
关于list的排序,使用sort()
函数即可
完整代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
const int N = 110;
int a[N];
set<int> s;
int n, t;
int main()
{
cin >> n;
while (n--)
{
cin >> t;
s.insert(t);
}
int tag = 0;
for (const auto &elem : s)
{
a[tag++] = elem;
}
sort(a, a + tag); // SORT
cout << tag << endl;
for (int i = 0; i < tag; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
2.3 洛谷题单P1102
题目信息:
思路:
此题使用map
- 优化小巧思:将A-B=C,转换为A-C=B,这样就可以提前存储好所有A-C的值,遍历map(存储了B的值),即可获得最后结果
- 需要注意使用long long类型,根据题目信息,可以看到数据范围超过int类型
完整代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
const int N = 200010;
LL v[N];
map<LL, LL> a;
int n;
LL c;
LL ans = 0;
int main()
{
cin >> n >> c;
for (int i = 0; i < n; i++)
{
cin >> v[i];
a[v[i]]++; // satisified B
v[i] -= c;
}
for (int i = 0; i < n; i++)
ans += a[v[i]];
cout << ans << endl;
return 0;
}
2.4 洛谷题单P5250
题目信息:
思路:
迭代器可以高效遍历
lower_bound
可以在 O(log n)
时间内找到不小于 l
的第一个元素的迭代器
完整代码:
#include <iostream>
#include <set>
using namespace std;
int main()
{
int n;
set<int> a;
cin >> n;
while (n--)
{
int op, l;
cin >> op >> l;
if (op == 1)
{
if (a.count(l))
cout << "Already Exist" << endl;
else
a.insert(l);
}
else // 2
{
if (a.empty())
{
cout << "Empty" << endl;
continue;
}
auto it = a.lower_bound(l);
if (it != a.end() && *it == l)
{
cout << l << endl;
a.erase(it);
}
else
{
// 这里,it是lower_bound返回的迭代器,它指向第一个不小于l的元素
auto it_lower = it; // it_lower 是指向第一个不小于 l 的元素的迭代器
// it_upper 是指向 it 之前的元素,如果 it 是 a.begin(),则 it_upper 设为 a.end()(表示不存在)
auto it_upper = (it == a.begin()) ? a.end() : prev(it);
int closest; // 用于存储最接近的木材长度
// 如果 it 是 a.end(),说明没有不小于 l 的元素,那么选择 it_upper
if (it == a.end())
{
closest = *it_upper;
}
// 如果 it 是 a.begin(),说明 l 小于或等于集合中的最小元素,那么选择 it
else if (it == a.begin())
{
closest = *it;
}
// 否则,比较 it 和 it_upper 指向的元素,选择最接近 l 的那个
else
{
closest = (l - *it_upper <= *it - l) ? *it_upper : *it;
}
cout << closest << endl; // 输出最接近的木材长度
a.erase(closest); // 从集合中删除该长度的木材
}
}
}
return 0;
}
2.5 洛谷题单P5266
题目信息:
思路:
此题很简单,熟悉map相关操作即可
- map查找对应元素
map[key]
- map删除对应元素
map.erase(key)
- 统计元素总数
map.size()
完整代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int N = 100010;
int n;
map<string, int> a;
int op;
long long score;
string name;
int main()
{
cin >> n;
while (n--)
{
cin >> op;
if (op == 1)
{
cin >> name >> score;
// if (!a.count(name))
a[name] = score;
cout << "OK" << endl;
}
else if (op == 2)
{
cin >> name;
if (a.count(name))
cout << a[name] << endl;
else
cout << "Not found" << endl;
}
else if (op == 3)
{
cin >> name;
if (a.count(name))
{
a.erase(name);
cout << "Deleted successfully" << endl;
}
else
cout << "Not found" << endl;
}
else
{
// op==4
cout << a.size() << endl;
}
}
}
参考资料
1: AcWing 算法基础课