[数据结构与算法基础] STL 介绍及相关练习

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 算法基础课

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值