1
cpp
string nextStr(const string& ssp, const string& s){}
//const可以保证函数不会修改ssp的值,&避免向量的拷贝。
Q1:函数的参数为什么不是 vector <string> strs?
-
避免不必要的拷贝
vector<string>
是一个容器,可能包含大量字符串。如果按值传递(vector<string> strs
),函数会创建整个容器的副本(包括所有字符串的拷贝),这会消耗额外的时间 (拷贝操作)和内存 (存储副本)。而使用引用
&
传递时,函数直接访问原始容器,不会产生任何拷贝,效率更高。 -
const则保证不会修改ssp
按值传递与按参传递
函数的定义:
cpp
类型名 函数名( 形式参数)
{
函数体
}
一些比较烦的题解类型:
范围for循环
(38 封私信 / 26 条消息) C++ 11 新特性:基于范围的 for 循环 - 知乎
基本语法
for (declaration : expression) {
// 循环体
}
declaration
是当前范围内元素的声明,通常是一个变量定义,这个变量会依次取得 expression中每个元素的值。expression
是要迭代的序列,可以是花括号括起来的初始化列表、数组、容器类对象等,也可以是返回 string 字符串和容器对象的函数
unordered_map<string, vector<int>> map
中的每个元素都是 std::pair
类型(键值对),其结构是 C++ 标准库预定义的:
cpp
// 标准库中 pair 的简化定义
template <class T1, class T2>
struct pair {
T1 first; // 键(key)
T2 second; // 值(value)
};
T1、T2是类型包括结构类型、整型等
范围for循环
for(元素类型 变量名 : 容器){.........}
典中典
cpp
unordered_map<string,vector<int>> map;
for(auto& t : map)
{
vector<string> tempres;
for(auto& index : t.second)
{
tempres.push_back(strs[index]);
}
res.push_back(tempres);
}
map 是一个二维向量,或者叫他现在的身份 哈希表!
例子:ate 123
这个t是一个变量哈,他的类型是什么呢,pair!!!
以unordered_map<string,vector<int>> map;为例子
map[原像].push_back(像);当原像不存在时,他会自动创建一个,当存在时,那就在vector<int>中插入像
stl
容器
一、vector
(动态数组,最常用的容器)
vector
类似 "可自动扩容的数组",支持随机访问,适合需要频繁添加 / 删除尾部元素的场景。
vector <类型> 容器名(初始的元素数目,元素初值);
vector <int> v;//整数,默认初值为0,指针nullptr
vector <int> v(3);
vector <int> v(3,3);
vector <int> v={1,2,3};
二维vector:
cpp
#include <vector>
using namespace std;
// 方式1:直接初始化m行n列,值为0
vector<vector<int>> mat(m, vector<int>(n));
// 方式2:初始化m行n列,值为5
vector<vector<int>> mat(m, vector<int>(n, 5));
// 方式3:动态构建(先创建空行,再逐行添加)
vector<vector<int>> mat;
for (int i = 0; i < m; i++) {
vector<int> row; // 每行可以是不同长度(如邻接表)
for (int j = 0; j < n; j++) {
row.push_back(i * j);
}
mat.push_back(row);
}
// 方式4:列表初始化(已知元素时)
vector<vector<int>> mat = {{1,2,3}, {4,5,6}, {7,8,9}};
vector<vector<string>> graph(26);
这里先创建一个二十六行的vector,之后graph[i]="adfs",相当于邻接表,在每一行后插入新元素
核心操作
cpp
// 访问元素(行索引i,列索引j)
int val = mat[i][j]; // 无越界检查
int val = mat.at(i).at(j); // 有越界检查(调试用)
// 遍历二维vector(三种方式)
// 方式1:下标遍历
for (int i = 0; i < mat.size(); i++) {
for (int j = 0; j < mat[i].size(); j++) {
cout << mat[i][j] << " ";
}
cout << endl;
}
// 方式2:迭代器遍历
for (auto it = mat.begin(); it != mat.end(); ++it) { // it指向一行
for (auto jt = it->begin(); jt != it->end(); ++jt) { // jt指向元素
cout << *jt << " ";
}
cout << endl;
}
// 方式3:范围for循环(C++11+)
for (auto& row : mat) { // row是每行的引用(避免拷贝)
for (int x : row) {
cout << x << " ";
}
cout << endl;
}
// 清空某一行
mat[0].clear();
// 清空整个二维vector
mat.clear();
场景示例:
vector高频操作
- 邻接表(图的存储):
vector<vector<int>> adj(n)
,adj[u].push_back(v)
表示边 u→v; - 动态规划表:
vector<vector<int>> dp(m, vector<int>(n, -1))
存储状态。
操作 | 语法示例 | 时间复杂度 | 场景 |
---|---|---|---|
排序(升序) | sort(v.begin(), v.end()) |
O(n log n) | 需有序序列的场景(二分查找等) |
排序(降序) | sort(v.begin(), v.end(), greater<int>()) |
O(n log n) | 找前 K 大元素等 |
自定义排序 | sort(v.begin(), v.end(), cmp) |
O(n log n) | 按结构体字段排序等 |
二分查找(存在性) | binary_search(v.begin(), v.end(), x) |
O(log n) | 判断元素是否在有序数组中 |
二分找第一个≥x | lower_bound(v.begin(), v.end(), x) |
O(log n) | 找插入位置、统计≥x 的元素数 |
二分找第一个>x | upper_bound(v.begin(), v.end(), x) |
O(log n) | 统计>x 的元素数、区间划分 |
去重(需先排序) | auto last = unique(v.begin(), v.end()); v.erase(last, v.end()) |
O(n) | 移除相邻重复元素 |
反转 | reverse(v.begin(), v.end()) |
O(n) | 翻转字符串、数组 |
填充 | fill(v.begin(), v.end(), 0) |
O(n) | 初始化数组为特定值 |
求最大值 | *max_element(v.begin(), v.end()) |
O(n) | 找序列最大值 |
求最小值 | *min_element(v.begin(), v.end()) |
O(n) | 找序列最小值 |
求和(C++17+) | accumulate(v.begin(), v.end(), 0) |
O(n) | 计算元素总和(需 #include <numeric>) |
cpp
vector<int> v = {3, 1, 4, 1, 5, 9};
// 排序(升序)
sort(v.begin(), v.end()); // v变为[1,1,3,4,5,9]
// 去重(需先排序)
auto last = unique(v.begin(), v.end()); // 移动重复元素到尾部,返回第一个重复元素的位置
v.erase(last, v.end()); // v变为[1,3,4,5,9]
// 二分查找第一个≥4的元素
auto it = lower_bound(v.begin(), v.end(), 4); // 指向4(索引2)
int pos = it - v.begin(); // 转换为下标:2
// 自定义排序(按绝对值从大到小)
vector<int> v2 = {-3, 1, -5, 2};
sort(v2.begin(), v2.end(), [](int a, int b) {
return abs(a) > abs(b); // 匿名函数作为比较器
}); // v2变为[-5, -3, 2, 1]
函数 | 作用 | 例子(假设 vector<int> v ) |
---|---|---|
v.size() |
返回元素个数 | int n = v.size(); (如果有 3 个元素,n=3) |
v.empty() |
判断是否为空(无元素) | if(v.empty()) { ... } |
v.push_back(x) |
在尾部添加元素 x |
v.push_back(5); (尾部新增 5) |
v.pop_back() |
删除尾部元素(无返回值) | v.pop_back(); (删除最后一个元素) |
v.clear() |
清空所有元素(容器变为空) | v.clear(); |
v[i] |
访问第 i 个元素(下标从 0 开始) |
int val = v[2]; (获取第 3 个元素) |
v.resize(n) |
调整容器大小为 n (多删少补默认值) |
v.resize(5); (调整为 5 个元素) |
cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 初始化一个vector,包含元素 {1, 2, 3}
vector<int> v = {1, 2, 3};
// 1. v.size():返回元素个数
int n = v.size();
cout << "初始元素个数:" << n << endl; // 输出:3
// 2. v.empty():判断是否为空
if (v.empty()) {
cout << "vector为空" << endl;
} else {
cout << "vector不为空" << endl; // 输出:vector不为空
}
// 3. v.push_back(x):在尾部添加元素x
v.push_back(4); // 尾部添加4,此时v为 {1, 2, 3, 4}
v.push_back(5); // 尾部添加5,此时v为 {1, 2, 3, 4, 5}
cout << "添加元素后,元素个数:" << v.size() << endl; // 输出:5
// 4. v[i]:访问第i个元素(下标从0开始)
int val = v[2]; // 访问下标2的元素(第3个元素)
cout << "下标2的元素值:" << val << endl; // 输出:3
// 5. v.pop_back():删除尾部元素
v.pop_back(); // 删除尾部的5,此时v为 {1, 2, 3, 4}
cout << "删除尾部元素后,元素个数:" << v.size() << endl; // 输出:4
cout << "当前尾部元素:" << v[v.size() - 1] << endl; // 输出:4(最后一个元素)
// 6. v.resize(n):调整大小为n(原元素数<span style="text-decoration: underline;">n时补默认值0,>n时删除多余元素)
v.resize(5); // 原大小为4,调整为5,补1个0,此时v为 {1, 2, 3, 4, 0}
cout << "resize(5)后,元素为:";
for (int num : v) {
cout << num << " "; // 输出:1 2 3 4 0
}
cout << endl;
// 7. v.clear():清空所有元素
v.clear();
cout << "clear()后,元素个数:" << v.size() << endl; // 输出:0
if (v.empty()) {
cout << "clear()后,vector为空" << endl; // 输出:clear()后,vector为空
}
return 0;
}
二、queue
(队列,先进先出 FIFO)
queue
类似 "排队",只能从队尾添加元素,从队首删除元素,适合 BFS 等场景。
函数 | 作用 | 例子(假设 queue<string> q ) |
---|---|---|
q.size() |
返回队列中元素个数 | int n = q.size(); |
q.empty() |
判断队列是否为空 | while(!q.empty()) { ... } (非空则循环) |
q.push(x) |
在队尾添加元素 x |
q.push("abc"); (队尾加入 "abc") |
q.pop() |
删除队首元素(无返回值,必须先判空) | q.pop(); (删除最前面的元素) |
q.front() |
获取队首元素(不删除,必须先判空) | string s = q.front(); (取最前面的元素) |
三、unordered_set
(无序集合,元素不重复)
unordered_set
类似 "无重复元素的袋子",查找速度快,适合记录 "已访问""去重" 等场景。
函数 | 作用 | 例子(假设 unordered_set<int> s ) |
---|---|---|
s.size() |
返回元素个数 | int n = s.size(); |
s.empty() |
判断是否为空 | if(s.empty()) { ... } |
s.insert(x) |
插入元素 x (若已存在则不插入) |
s.insert(10); (插入 10) |
s.find(x) |
查找元素 x ,返回迭代器: 找到则指向 x ,否则指向 s.end() |
if(s.find(10) != s.end()) { ... } (判断 10 是否存在) |
s.erase(x) |
删除元素 x (若存在) |
s.erase(10); (删除 10) |
s.clear() |
清空所有元素 | s.clear(); |
四、string
(字符串,字符容器)
string
是存储字符的容器,本质是 char
类型的数组封装,支持字符串拼接、比较等操作。
函数 | 作用 | 例子(假设 string str = "abc" ) |
---|---|---|
str.size() |
返回字符个数(长度) | int len = str.size(); (len=3) |
str.empty() |
判断字符串是否为空(长度为 0) | if(str.empty()) { ... } |
str += c |
拼接字符 c 或字符串 |
str += 'd'; (str 变为 "abcd") |
str.c_str() |
转换为 C 风格字符串(const char* ) |
cout << str.c_str(); (兼容 C 语言函数) |
str.substr(i, n) |
从下标 i 开始,截取长度为 n 的子串 |
string sub = str.substr(1, 2); (sub 为 "bc") |
str.clear() |
清空字符串(变为空串) | str.clear(); (str 变为 "") |
str[i] |
访问第 i 个字符(下标从 0 开始) |