专为算法刷题设计的头文件使用指南 - 避坑版
C++标准输入输出库,提供cin、cout、endl等对象进行格式化输入输出。
xusing namespace std;
// 基础输入输出int n;cin >> n;cout << n << endl;
// 多个变量int a, b, c;cin >> a >> b >> c;cout << a << " " << b << " " << c << endl;
// 加速IO(竞赛必备)ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// 链式输入输出cout << "Result: " << a + b << endl;类型安全,自动识别数据类型
支持自定义类型的重载
比printf/scanf更易用(但默认较慢)
xxxxxxxxxx// ❌ 错误:只能读到第一个空格前string s;cin >> s; // 输入"hello world",只得到"hello"
// ✅ 正确:读取整行string s;getline(cin, s); // 得到"hello world"xxxxxxxxxx// ❌ 错误示例int n;cin >> n;string s;getline(cin, s); // s会是空字符串!
// ✅ 正确:清除缓冲区的换行符int n;cin >> n;cin.ignore(); // 忽略换行符string s;getline(cin, s);xxxxxxxxxx// ❌ 错误:加速后混用会导致输出顺序错乱ios::sync_with_stdio(false);cin >> n;printf("%d\n", n); // 可能不按预期输出
// ✅ 正确:统一使用cin/cout或scanf/printfios::sync_with_stdio(false);cin >> n;cout << n << endl;xxxxxxxxxx// endl会刷新缓冲区,较慢cout << n << endl;
// '\n'不刷新缓冲区,更快(推荐)cout << n << '\n';
// 大量输出时差异明显for(int i = 0; i < 100000; i++) { cout << i << '\n'; // 快 // cout << i << endl; // 慢}xxxxxxxxxx// 方法1:while(cin >> n)int n;while(cin >> n) { // 处理n}
// 方法2:检查EOFwhile(scanf("%d", &n) != EOF) { // 处理n}
// 方法3:先读取数据量int t;cin >> t;while(t--) { // 处理每组数据}xxxxxxxxxx
double pi = 3.1415926535;
// 保留2位小数cout << fixed << setprecision(2) << pi << endl; // 3.14
// 科学计数法cout << scientific << pi << endl; // 3.14e+00
// 恢复默认cout << defaultfloat << pi << endl;在默认情况下,cin/cout 比 scanf/printf 慢非常多。因为 C++ 为了保证混合输入输出时的兼容性,强制把 cin/cout 和 C 语言的 stdio 缓冲区绑定在了一起。在遇到百万级别的数据输入时,不关同步必然超时(Time Limit Exceeded)。
✅ 考场必备的加速咒语(写在 main 函数第一行):
xxxxxxxxxxios::sync_with_stdio(false); // 打破 C++ 和 C 的输入输出流绑定cin.tie(NULL); // 解除 cin 和 cout 的绑定(默认 cin 执行前会刷新 cout)cout.tie(NULL); // 解除 cout 绑定的非必要刷新⚠️ 致命陷阱: 加了这三行代码后,绝对不能再在代码中混用 scanf/printf/puts!否则缓冲区的剥离会导致输入输出顺序彻底错乱。
xxxxxxxxxx
// 常用格式符int n;scanf("%d", &n); // intprintf("%d\n", n);
long long ll;scanf("%lld", &ll); // long longprintf("%lld\n", ll);
double d;scanf("%lf", &d); // doubleprintf("%.2lf\n", d); // 保留2位小数
char c;scanf(" %c", &c); // 注意空格,跳过空白字符
char s[100];scanf("%s", s); // 字符串(遇空格停止)printf("%s\n", s);
// 读取整行(包含空格)char line[1000];fgets(line, sizeof(line), stdin);动态大小的数组,自动管理内存,是STL中最常用的容器。
xxxxxxxxxxusing namespace std;
// 声明vector<int> v; // 空vectorvector<int> v(10); // 10个元素,默认值0vector<int> v(10, 5); // 10个元素,值都是5vector<int> v = {1, 2, 3, 4, 5}; // 初始化列表vector<int> v(arr, arr + n); // 从数组构造
// 基本操作v.push_back(x); // 尾部添加v.pop_back(); // 删除尾部v.size(); // 元素个数v.empty(); // 是否为空v.clear(); // 清空v.front(); // 第一个元素v.back(); // 最后一个元素v[i]; // 访问第i个元素v.at(i); // 带边界检查的访问
// 插入删除v.insert(v.begin() + i, x); // 在位置i插入xv.erase(v.begin() + i); // 删除位置i的元素v.erase(v.begin() + i, v.begin() + j); // 删除[i, j)
// 大小调整v.resize(n); // 改变大小为nv.reserve(n); // 预留空间(不改变size)
// 二维vectorvector<vector<int>> matrix(n, vector<int>(m, 0));动态大小,不需要预先知道数组长度
自动内存管理,不会内存泄漏
支持所有STL算法
比数组更安全(at()会检查边界)
xxxxxxxxxxvector<int> v;// ❌ 错误:size()是unsigned,减法可能溢出for(int i = 0; i < v.size() - 1; i++) { // v为空时溢出! // ...}
// ✅ 正确方法1:转为intfor(int i = 0; i < (int)v.size() - 1; i++) { // ...}
// ✅ 正确方法2:先判断if(!v.empty()) { for(int i = 0; i < v.size() - 1; i++) { // ... }}
// ✅ 正确方法3:使用有符号变量int n = v.size();for(int i = 0; i < n - 1; i++) { // ...}xxxxxxxxxxvector<int> v = {1, 2, 3, 4, 5};
// ❌ 错误:erase后迭代器失效for(auto it = v.begin(); it != v.end(); it++) { if(*it % 2 == 0) { v.erase(it); // it失效! }}
// ✅ 正确:erase返回下一个有效迭代器for(auto it = v.begin(); it != v.end(); ) { if(*it % 2 == 0) { it = v.erase(it); // 更新it } else { it++; }}
// ❌ 错误:push_back可能导致扩容,所有迭代器失效for(auto it = v.begin(); it != v.end(); it++) { v.push_back(*it); // 危险!}
// ✅ 正确:先记录大小int n = v.size();for(int i = 0; i < n; i++) { v.push_back(v[i]);}xxxxxxxxxx// ❌ 错误:所有行共享同一个vectorvector<int> row(m, 0);vector<vector<int>> matrix(n, row);matrix[0][0] = 1; // 不会影响其他行(这个是对的)
// ❌ 错误:这样会有问题vector<vector<int>> matrix(n); // n个空vectormatrix[0].push_back(1); // 第0行有1个元素// matrix[1][0]; // 越界!第1行还是空的
// ✅ 正确:每行独立初始化vector<vector<int>> matrix(n, vector<int>(m, 0));
// ✅ 正确:逐行初始化vector<vector<int>> matrix(n);for(int i = 0; i < n; i++) { matrix[i].resize(m, 0);}xxxxxxxxxxvector<int> v = {1, 2, 3};
// ❌ 错误:[]不检查边界cout << v[10] << endl; // 未定义行为,可能崩溃
// ✅ 正确:at()会检查边界并抛出异常try { cout << v.at(10) << endl;} catch(out_of_range& e) { cout << "越界!" << endl;}
// ✅ 最佳:先判断if(i >= 0 && i < v.size()) { cout << v[i] << endl;}xxxxxxxxxxvector<int> v(1000000);v.clear(); // size变为0,但capacity不变
// 真正释放内存vector<int>().swap(v); // 或v.shrink_to_fit(); // C++11xxxxxxxxxxvector<int> v1 = {1, 2, 3};vector<int> v2 = {1, 2, 4};
// 字典序比较v1 < v2; // truev1 == v2; // false当 vector 中存储的是 pair 或自定义结构体时,push_back 会先创建一个临时对象,再拷贝/移动进去。而 emplace_back 支持直接在容器末尾原地构造对象,省去了拷贝的开销。
xxxxxxxxxxvector<pair<int, int>> v; // ❌ 略慢:需要大括号构造临时 pair v.push_back({1, 2}); // ✅ 更快:直接传入构造参数,原地生成 v.emplace_back(1, 2); 提供各种算法函数,如排序、查找、反转等,是刷题必备的头文件。
xxxxxxxxxxusing namespace std;
vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
// 排序sort(v.begin(), v.end()); // 升序sort(v.begin(), v.end(), greater<int>()); // 降序
// 自定义排序sort(v.begin(), v.end(), [](int a, int b) { return a > b; // 降序});
// 二分查找(必须已排序)bool found = binary_search(v.begin(), v.end(), 5);
// lower_bound: 第一个>=x的位置auto it = lower_bound(v.begin(), v.end(), 5);int pos = it - v.begin(); // 获取下标
// upper_bound: 第一个>x的位置auto it = upper_bound(v.begin(), v.end(), 5);
// 反转reverse(v.begin(), v.end());
// 去重(必须先排序)sort(v.begin(), v.end());v.erase(unique(v.begin(), v.end()), v.end());
// 最大最小值int maxVal = *max_element(v.begin(), v.end());int minVal = *min_element(v.begin(), v.end());
// 填充fill(v.begin(), v.end(), 0);
// 全排列sort(v.begin(), v.end());do { // 处理当前排列} while(next_permutation(v.begin(), v.end()));
// 部分排序(前k个最小)partial_sort(v.begin(), v.begin() + k, v.end());
// 第k小元素nth_element(v.begin(), v.begin() + k, v.end());高效实现,经过优化
代码简洁,避免手写错误
通用性强,适用于各种容器
xxxxxxxxxx// ❌ 错误:使用<=会导致未定义行为sort(v.begin(), v.end(), [](int a, int b) { return a <= b; // 错误!});
// ✅ 正确:使用<sort(v.begin(), v.end(), [](int a, int b) { return a < b;});
// 严格弱序要求:// 1. 反自反性:comp(a, a) == false// 2. 非对称性:comp(a, b) == true 则 comp(b, a) == false// 3. 传递性:comp(a, b) && comp(b, c) 则 comp(a, c)xxxxxxxxxxvector<int> v = {3, 1, 4, 1, 5};
// ❌ 错误:未排序就二分bool found = binary_search(v.begin(), v.end(), 4); // 结果不可靠
// ✅ 正确:先排序sort(v.begin(), v.end());bool found = binary_search(v.begin(), v.end(), 4);xxxxxxxxxxvector<int> v = {1, 2, 2, 2, 3, 4, 5};sort(v.begin(), v.end());
// lower_bound: 第一个 >= targetauto it1 = lower_bound(v.begin(), v.end(), 2);cout << *it1 << endl; // 2(第一个2)cout << it1 - v.begin() << endl; // 1(下标)
// upper_bound: 第一个 > targetauto it2 = upper_bound(v.begin(), v.end(), 2);cout << *it2 << endl; // 3(第一个大于2的)cout << it2 - v.begin() << endl; // 4(下标)
// 统计元素个数int count = upper_bound(v.begin(), v.end(), 2) - lower_bound(v.begin(), v.end(), 2); // 3个2
// 查找不存在的元素auto it3 = lower_bound(v.begin(), v.end(), 10);if(it3 == v.end()) { cout << "不存在" << endl;}xxxxxxxxxxvector<int> v = {1, 2, 2, 3, 3, 3, 4};
// ❌ 错误:unique不改变sizeunique(v.begin(), v.end());cout << v.size() << endl; // 还是7
// ✅ 正确:配合erase删除sort(v.begin(), v.end()); // 必须先排序v.erase(unique(v.begin(), v.end()), v.end());cout << v.size() << endl; // 4
// unique返回的是"新结尾"的迭代器// 原理:[1, 2, 3, 4, 3, 3, 4] -> unique后变为 [1, 2, 3, 4, ?, ?, ?]// ^返回这里xxxxxxxxxxvector<int> v = {1, 2, 3};
// ❌ 错误:未排序,会漏掉一些排列v = {3, 2, 1};do { // 只会生成一个排列} while(next_permutation(v.begin(), v.end()));
// ✅ 正确:从最小排列开始sort(v.begin(), v.end());do { // 打印当前排列 for(int x : v) cout << x << " "; cout << endl;} while(next_permutation(v.begin(), v.end()));
// 生成所有排列:3! = 6个// 1 2 3// 1 3 2// 2 1 3// 2 3 1// 3 1 2// 3 2 1xxxxxxxxxxvector<int> v = {3, 1, 4, 1, 5};
// ❌ 错误:直接当值用int maxVal = max_element(v.begin(), v.end()); // 错误!
// ✅ 正确:解引用int maxVal = *max_element(v.begin(), v.end());
// 获取最大值的下标auto it = max_element(v.begin(), v.end());int idx = it - v.begin();cout << "最大值" << *it << "在下标" << idx << endl;
// 空容器会导致未定义行为vector<int> empty;// int maxVal = *max_element(empty.begin(), empty.end()); // 危险!
// 安全做法if(!empty.empty()) { int maxVal = *max_element(empty.begin(), empty.end());}xxxxxxxxxx// sort平均O(n log n),最坏O(n log n)(C++11后保证)// 但对于特殊数据可能较慢
// 对于大量重复元素,可以用stable_sortvector<int> v(100000, 1); // 全是1stable_sort(v.begin(), v.end()); // 保持相对顺序
// 或者先去重再排序sort(v.begin(), v.end());v.erase(unique(v.begin(), v.end()), v.end());xxxxxxxxxx// 对pair排序vector<pair<int, int>> v = {{1, 3}, {2, 1}, {1, 2}};
// 默认先按first排序,first相同按second排序sort(v.begin(), v.end());// 结果:{1, 2}, {1, 3}, {2, 1}
// 按second排序sort(v.begin(), v.end(), [](auto& a, auto& b) { return a.second < b.second;});
// 按first降序,second升序sort(v.begin(), v.end(), [](auto& a, auto& b) { if(a.first != b.first) return a.first > b.first; return a.second < b.second;});
// 对结构体排序struct Student { string name; int score;};
vector<Student> students;sort(students.begin(), students.end(), [](Student& a, Student& b) { return a.score > b.score; // 按分数降序});C++标准库的字符串类,比C风格字符串更安全、更易用。
xxxxxxxxxxusing namespace std;
// 声明与初始化string s = "hello";string s(10, 'a'); // "aaaaaaaaaa"string s(s2); // 拷贝构造
// 基本操作s.length() / s.size(); // 长度s.empty(); // 是否为空s.clear(); // 清空s[i]; // 访问第i个字符s.at(i); // 带边界检查
// 拼接s += "world";s = s + " !";s.append("!");
// 子串s.substr(pos); // 从pos到末尾s.substr(pos, len); // 从pos开始长度len
// 查找s.find(str); // 查找子串,返回位置或string::nposs.find(str, pos); // 从pos开始查找s.rfind(str); // 从后往前查找s.find_first_of("aeiou"); // 查找第一个元音s.find_last_of("aeiou"); // 查找最后一个元音
// 插入删除s.insert(pos, str); // 在pos位置插入s.erase(pos, len); // 删除从pos开始长度len
// 替换s.replace(pos, len, str); // 替换
// 比较s1 == s2;s1 < s2; // 字典序
// 转换int num = stoi(s); // string转intlong long num = stoll(s); // string转long longdouble d = stod(s); // string转doublestring s = to_string(123); // 数字转string自动内存管理
丰富的成员函数
支持运算符重载(+, ==, <等)
比C字符串更安全
xxxxxxxxxxstring s = "hello world";
// ❌ 错误:find返回size_t(无符号),不能用-1判断if(s.find("abc") == -1) { // 错误! // ...}
// ✅ 正确:使用string::nposif(s.find("abc") == string::npos) { cout << "未找到" << endl;}
// ✅ 或者判断是否不等于nposif(s.find("world") != string::npos) { cout << "找到了" << endl;}
// string::npos的值通常是-1(转为size_t后是最大值)cout << string::npos << endl; // 18446744073709551615(64位)xxxxxxxxxxstring s = "hello";
// ❌ 错误:长度超出范围不会报错,自动截断string sub = s.substr(2, 100); // "llo"(不是错误)
// ❌ 错误:起始位置超出范围会抛出异常try { string sub = s.substr(10); // 抛出out_of_range} catch(out_of_range& e) { cout << "越界" << endl;}
// ✅ 正确:先检查if(pos < s.length()) { string sub = s.substr(pos, len);}
// substr(pos):从pos到末尾string sub = s.substr(2); // "llo"
// substr(pos, len):从pos开始长度lenstring sub = s.substr(2, 2); // "ll"xxxxxxxxxx// ❌ 低效:每次+=都可能重新分配内存string s;for(int i = 0; i < 100000; i++) { s += "a"; // O(n²)}
// ✅ 高效:预留空间string s;s.reserve(100000); // 预留空间for(int i = 0; i < 100000; i++) { s += "a"; // O(n)}
// ✅ 或使用构造函数string s(100000, 'a');xxxxxxxxxxstring s1 = "abc";string s2 = "abd";
s1 < s2; // true(字典序)s1 == s2; // false
// 数字字符串的比较string n1 = "10";string n2 = "2";n1 < n2; // true(字典序:"1" < "2")
// ✅ 正确:转为数字比较int num1 = stoi(n1);int num2 = stoi(n2);num1 < num2; // false(10 > 2)xxxxxxxxxx// ❌ 错误:非法字符串会抛出异常string s = "abc";int n = stoi(s); // 抛出invalid_argument
// ❌ 错误:超出范围会抛出异常string s = "99999999999999999999";int n = stoi(s); // 抛出out_of_range
// ✅ 正确:捕获异常try { int n = stoi(s);} catch(invalid_argument& e) { cout << "非法输入" << endl;} catch(out_of_range& e) { cout << "超出范围" << endl;}
// stoi会忽略前导空格和后面的非数字字符string s = " 123abc";int n = stoi(s); // 123
// 获取转换了多少字符size_t pos;int n = stoi(s, &pos);cout << "转换了" << pos << "个字符" << endl;xxxxxxxxxxstring s = "hello";
// ❌ 错误:单引号是字符,双引号是字符串s += 'a'; // 正确:添加字符s += "a"; // 正确:添加字符串s = s + 'a'; // 错误!不能直接相加
// ✅ 正确s.push_back('a'); // 添加字符s += 'a'; // 添加字符s += "a"; // 添加字符串s = s + "a"; // 字符串拼接xxxxxxxxxxstring s = "hello";
// 遍历(只读)for(char c : s) { cout << c;}
// 遍历(可修改)for(char& c : s) { c = toupper(c);}cout << s << endl; // "HELLO"
// 使用下标修改for(int i = 0; i < s.length(); i++) { s[i] = toupper(s[i]);}C++数学函数库,提供常用数学运算函数。
xxxxxxxxxxusing namespace std;
// 基本运算sqrt(x); // 平方根pow(x, y); // x的y次方abs(x); // 绝对值(整数用abs,浮点用fabs)fabs(x); // 浮点数绝对值
// 取整ceil(x); // 向上取整floor(x); // 向下取整round(x); // 四舍五入trunc(x); // 截断小数部分
// 对数log(x); // 自然对数(ln)log10(x); // 以10为底log2(x); // 以2为底(C++11)
// 三角函数sin(x); // 正弦(弧度)cos(x); // 余弦tan(x); // 正切asin(x); // 反正弦acos(x); // 反余弦atan(x); // 反正切atan2(y, x); // 返回y/x的反正切(考虑象限)
// 其他exp(x); // e^xfmod(x, y); // 浮点数取模hypot(x, y); // sqrt(x²+y²)高精度实现
跨平台一致性
处理特殊值(NaN, Inf)
xxxxxxxxxx// ❌ 低效:pow对整数也返回doubleint result = pow(2, 10); // 返回double,可能有精度误差
// ✅ 高效:整数幂用快速幂long long quickPow(long long a, long long b) { long long res = 1; while(b > 0) { if(b & 1) res *= a; a *= a; b >>= 1; } return res;}
// pow的精度问题cout << pow(10, 9) << endl; // 可能输出999999999.999999
// ✅ 正确:四舍五入int result = round(pow(10, 9));
// 对于小整数幂,直接乘更快int x2 = x * x; // 比pow(x, 2)快int x3 = x * x * x; // 比pow(x, 3)快xxxxxxxxxx// ❌ 错误:负数的平方根是NaNdouble result = sqrt(-1); // NaN(Not a Number)
// 检查NaNif(isnan(result)) { cout << "结果是NaN" << endl;}
// ✅ 正确:先判断if(x >= 0) { double result = sqrt(x);}
// 判断浮点数是否有效isnan(x); // 是否为NaNisinf(x); // 是否为无穷大isfinite(x); // 是否为有限值xxxxxxxxxxdouble a = 0.1 + 0.2;double b = 0.3;
// ❌ 错误:直接比较if(a == b) { // false! cout << "相等" << endl;}
// ✅ 正确:使用误差范围const double EPS = 1e-9;if(fabs(a - b) < EPS) { cout << "相等" << endl;}
// 或使用函数bool equal(double a, double b) { return fabs(a - b) < 1e-9;}xxxxxxxxxxint a = 5, b = 2;
// ❌ 错误:整数除法double result = a / b; // 2.0(先算5/2=2,再转double)
// ✅ 正确:至少一个转为doubledouble result = (double)a / b; // 2.5double result = 1.0 * a / b; // 2.5double result = a / (double)b; // 2.5xxxxxxxxxxint x = -5;double y = -5.5;
// abs用于整数int result1 = abs(x); // 5
// fabs用于浮点数double result2 = fabs(y); // 5.5
// ❌ 错误:混用可能导致精度丢失int result = abs(-5.5); // 可能是5(截断)
// ✅ 正确:根据类型选择double result = fabs(-5.5); // 5.5
// C++11:通用absauto result = std::abs(-5); // intauto result = std::abs(-5.5); // doublexxxxxxxxxx// ❌ 错误:sin/cos等使用弧度,不是角度double result = sin(90); // 不是1!
// ✅ 正确:角度转弧度const double PI = acos(-1); // 或 3.14159265358979323846double radians = 90 * PI / 180;double result = sin(radians); // 1
// 弧度转角度double degrees = radians * 180 / PI;xxxxxxxxxx// log是自然对数(ln),底数是edouble result = log(10); // ln(10) ≈ 2.302585
// log10是常用对数,底数是10double result = log10(100); // 2
// log2是以2为底(C++11)double result = log2(8); // 3
// 换底公式:log_a(b) = log(b) / log(a)double log_a_b = log(b) / log(a);xxxxxxxxxxdouble x = 2.7;double y = -2.7;
// ceil:向上取整(朝正无穷)ceil(x); // 3ceil(y); // -2
// floor:向下取整(朝负无穷)floor(x); // 2floor(y); // -3
// round:四舍五入round(x); // 3round(y); // -3
// trunc:截断小数(朝0)trunc(x); // 2trunc(y); // -2
// 注意:返回值是double,需要转换int result = (int)ceil(x);先进先出(FIFO)的数据结构,常用于BFS、任务调度等场景。
xxxxxxxxxxusing namespace std;
// 普通队列queue<int> q;
q.push(x); // 入队q.pop(); // 出队(无返回值)q.front(); // 队首元素q.back(); // 队尾元素q.empty(); // 是否为空q.size(); // 队列大小
// 双端队列deque<int> dq;
dq.push_back(x); // 尾部插入dq.push_front(x); // 头部插入dq.pop_back(); // 尾部删除dq.pop_front(); // 头部删除dq.front();dq.back();dq[i]; // 随机访问dq.empty();dq.size();
// 优先队列(大顶堆)priority_queue<int> pq;
pq.push(x); // 插入pq.pop(); // 删除堆顶pq.top(); // 获取堆顶pq.empty();pq.size();
// 小顶堆priority_queue<int, vector<int>, greater<int>> pq;queue:BFS、层序遍历、任务队列
deque:滑动窗口、单调队列
priority_queue:Dijkstra、Top K问题、贪心算法
xxxxxxxxxxqueue<int> q;q.push(1);q.push(2);
// ❌ 错误:pop()不返回值int x = q.pop(); // 编译错误!
// ✅ 正确:先front()再pop()int x = q.front();q.pop();
// 或者一起写while(!q.empty()) { int x = q.front(); q.pop(); // 处理x}xxxxxxxxxxqueue<int> q;
// ❌ 错误:空队列调用front()int x = q.front(); // 未定义行为!
// ✅ 正确:先判断if(!q.empty()) { int x = q.front();}
// BFS模板queue<int> q;q.push(start);while(!q.empty()) { int cur = q.front(); q.pop(); // 处理cur}xxxxxxxxxxpriority_queue<int> pq;pq.push(3);pq.push(1);pq.push(4);
cout << pq.top() << endl; // 4(最大值)
// 小顶堆(最小值在顶部)priority_queue<int, vector<int>, greater<int>> pq;pq.push(3);pq.push(1);pq.push(4);
cout << pq.top() << endl; // 1(最小值)xxxxxxxxxx// 对pair的优先队列priority_queue<pair<int, int>> pq; // 默认按first降序,first相同按second降序
// 自定义结构体struct Node { int val, idx; // ❌ 错误:operator<的含义是"小于" bool operator < (const Node& other) const { return val < other.val; // 这样会变成大顶堆! }};
// ✅ 正确:要小顶堆,需要反向比较struct Node { int val, idx; bool operator < (const Node& other) const { return val > other.val; // 小顶堆 }};
priority_queue<Node> pq;
// 或使用lambda(C++11)auto cmp = [](Node& a, Node& b) { return a.val > b.val; // 小顶堆};priority_queue<Node, vector<Node>, decltype(cmp)> pq(cmp);xxxxxxxxxx// deque支持随机访问,但比vector慢deque<int> dq;vector<int> v;
// 频繁随机访问:vector更快for(int i = 0; i < n; i++) { v[i] = i; // 快 dq[i] = i; // 慢}
// 频繁头部插入:deque更快for(int i = 0; i < n; i++) { dq.push_front(i); // O(1) v.insert(v.begin(), i); // O(n)}
// 使用场景:// - 只需要尾部操作 → vector// - 需要头尾操作 → deque// - 需要中间插入删除 → listxxxxxxxxxxpriority_queue<int> pq;pq.push(3);pq.push(1);pq.push(4);
// ❌ 错误:不能直接遍历for(int x : pq) { // 编译错误! cout << x;}
// ✅ 正确:逐个取出(会清空队列)while(!pq.empty()) { cout << pq.top() << " "; pq.pop();}
// 如果需要保留,先复制priority_queue<int> pq_copy = pq;while(!pq_copy.empty()) { cout << pq_copy.top() << " "; pq_copy.pop();}xxxxxxxxxx// 滑动窗口最大值vector<int> maxSlidingWindow(vector<int>& nums, int k) { deque<int> dq; // 存下标,保持递减 vector<int> res; for(int i = 0; i < nums.size(); i++) { // 移除窗口外的元素 while(!dq.empty() && dq.front() < i - k + 1) { dq.pop_front(); } // 维护单调性(递减) while(!dq.empty() && nums[dq.back()] < nums[i]) { dq.pop_back(); } dq.push_back(i); // 窗口形成后记录答案 if(i >= k - 1) { res.push_back(nums[dq.front()]); } } return res;}后进先出(LIFO)的数据结构,常用于括号匹配、表达式求值、DFS等场景。
xxxxxxxxxxusing namespace std;
stack<int> stk;
stk.push(x); // 入栈stk.pop(); // 出栈(无返回值)stk.top(); // 获取栈顶元素stk.empty(); // 是否为空stk.size(); // 栈大小
// 典型用法while(!stk.empty()) { int x = stk.top(); stk.pop(); // 处理x}括号匹配问题
表达式求值(中缀转后缀)
单调栈(找下一个更大/更小元素)
DFS的迭代实现
函数调用栈的模拟
xxxxxxxxxxstack<int> stk;stk.push(1);stk.push(2);
// ❌ 错误:pop()不返回值int x = stk.pop(); // 编译错误!
// ✅ 正确:先top()再pop()int x = stk.top();stk.pop();xxxxxxxxxxstack<int> stk;
// ❌ 错误:空栈调用top()int x = stk.top(); // 未定义行为!
// ✅ 正确:先判断if(!stk.empty()) { int x = stk.top();}xxxxxxxxxxstack<int> stk;stk.push(1);stk.push(2);stk.push(3);
// ❌ 错误:不能直接遍历for(int x : stk) { // 编译错误! cout << x;}
// ✅ 正确:逐个取出(会清空栈)while(!stk.empty()) { cout << stk.top() << " "; stk.pop();}
// 如果需要保留,先复制stack<int> stk_copy = stk;while(!stk_copy.empty()) { cout << stk_copy.top() << " "; stk_copy.pop();}xxxxxxxxxxbool isValid(string s) { stack<char> stk; for(char c : s) { if(c == '(' || c == '[' || c == '{') { stk.push(c); } else { // ❌ 错误:没有检查栈是否为空 // char top = stk.top(); // ✅ 正确:先判断 if(stk.empty()) return false; char top = stk.top(); stk.pop(); if(c == ')' && top != '(') return false; if(c == ']' && top != '[') return false; if(c == '}' && top != '{') return false; } } return stk.empty(); // 栈必须为空}xxxxxxxxxx// 找每个元素右边第一个比它大的元素vector<int> nextGreater(vector<int>& arr) { int n = arr.size(); vector<int> res(n, -1); stack<int> stk; // 存下标,保持单调递减 for(int i = 0; i < n; i++) { // 当前元素比栈顶大,说明找到了栈顶的答案 while(!stk.empty() && arr[stk.top()] < arr[i]) { res[stk.top()] = arr[i]; stk.pop(); } stk.push(i); } return res;}
// 找每个元素左边第一个比它大的元素vector<int> prevGreater(vector<int>& arr) { int n = arr.size(); vector<int> res(n, -1); stack<int> stk; for(int i = 0; i < n; i++) { // 维护单调递减栈 while(!stk.empty() && arr[stk.top()] <= arr[i]) { stk.pop(); } if(!stk.empty()) { res[i] = arr[stk.top()]; } stk.push(i); } return res;}xxxxxxxxxx// 递归DFSvoid dfs(int u, vector<vector<int>>& graph, vector<bool>& visited) { visited[u] = true; cout << u << " "; for(int v : graph[u]) { if(!visited[v]) { dfs(v, graph, visited); } }}
// 迭代DFS(用栈)void dfsIterative(int start, vector<vector<int>>& graph) { int n = graph.size(); vector<bool> visited(n, false); stack<int> stk; stk.push(start); while(!stk.empty()) { int u = stk.top(); stk.pop(); if(visited[u]) continue; visited[u] = true; cout << u << " "; // 注意:为了保持和递归相同的顺序,需要逆序入栈 for(int i = graph[u].size() - 1; i >= 0; i--) { int v = graph[u][i]; if(!visited[v]) { stk.push(v); } } }}有序集合,自动去重并排序,基于红黑树实现,时间复杂度O(log n)。
xxxxxxxxxxusing namespace std;
set<int> st;
st.insert(x); // 插入(自动去重)st.erase(x); // 删除值为x的元素st.erase(it); // 删除迭代器指向的元素st.count(x); // 是否存在(返回0或1)st.find(x); // 查找,返回迭代器st.size();st.empty();st.clear();
// 有序特性*st.begin(); // 最小元素*st.rbegin(); // 最大元素
// 二分查找auto it = st.lower_bound(x); // 第一个>=x的元素auto it = st.upper_bound(x); // 第一个>x的元素
// 遍历(有序)for(int x : st) { cout << x << " ";}
// multiset(允许重复)multiset<int> mst;mst.insert(1);mst.insert(1); // 可以重复mst.erase(1); // 删除所有1mst.erase(mst.find(1)); // 只删除一个1自动去重和排序
快速查找、插入、删除(O(log n))
需要维护有序集合
需要快速找到最小/最大值
xxxxxxxxxxset<int> st;st.insert(1);st.insert(1); // 不会插入,因为已存在
cout << st.size() << endl; // 1
// insert返回pair<iterator, bool>auto result = st.insert(2);if(result.second) { cout << "插入成功" << endl;} else { cout << "元素已存在" << endl;}xxxxxxxxxxset<int> st = {1, 2, 3, 4, 5};
// 方法1:按值删除st.erase(3); // 删除值为3的元素
// 方法2:按迭代器删除auto it = st.find(4);if(it != st.end()) { st.erase(it);}
// ❌ 错误:迭代器失效for(auto it = st.begin(); it != st.end(); it++) { if(*it % 2 == 0) { st.erase(it); // it失效! }}
// ✅ 正确:erase返回下一个迭代器for(auto it = st.begin(); it != st.end(); ) { if(*it % 2 == 0) { it = st.erase(it); // C++11 } else { it++; }}xxxxxxxxxxset<int> st = {1, 2, 3};
// count:返回0或1(set中元素唯一)if(st.count(2)) { cout << "存在" << endl;}
// find:返回迭代器auto it = st.find(2);if(it != st.end()) { cout << "找到了:" << *it << endl;}
// 性能:两者时间复杂度都是O(log n),但find更灵活xxxxxxxxxxset<int> st = {1, 3, 5, 7, 9};
// lower_bound:第一个>=x的元素auto it1 = st.lower_bound(5);cout << *it1 << endl; // 5
auto it2 = st.lower_bound(4);cout << *it2 << endl; // 5(第一个>=4的)
// upper_bound:第一个>x的元素auto it3 = st.upper_bound(5);cout << *it3 << endl; // 7
// 查找不存在的元素auto it4 = st.lower_bound(10);if(it4 == st.end()) { cout << "没有>=10的元素" << endl;}
// 查找范围内的元素个数int count = distance(st.lower_bound(3), st.upper_bound(7));cout << "[3, 7]范围内有" << count << "个元素" << endl; // 3个:3,5,7xxxxxxxxxxset<int> st = {3, 1, 4, 1, 5};
// 最小值int minVal = *st.begin();
// 最大值int maxVal = *st.rbegin(); // 或 *prev(st.end())
// ❌ 错误:空集合set<int> empty;// int minVal = *empty.begin(); // 未定义行为!
// ✅ 正确:先判断if(!empty.empty()) { int minVal = *empty.begin();}xxxxxxxxxxmultiset<int> mst = {1, 2, 2, 3, 3, 3};
// 统计某个值的个数int count = mst.count(3); // 3
// 删除所有值为x的元素mst.erase(3); // 删除所有3cout << mst.size() << endl; // 3(剩下1,2,2)
// 只删除一个mst.insert(3);mst.insert(3);auto it = mst.find(3);if(it != mst.end()) { mst.erase(it); // 只删除一个3}
// 获取某个值的范围auto range = mst.equal_range(2);for(auto it = range.first; it != range.second; it++) { cout << *it << " "; // 输出所有2}xxxxxxxxxx// 降序setset<int, greater<int>> st = {3, 1, 4, 1, 5};for(int x : st) { cout << x << " "; // 5 4 3 1}
// 自定义结构体struct Point { int x, y; bool operator < (const Point& other) const { if(x != other.x) return x < other.x; return y < other.y; }};
set<Point> points;points.insert({1, 2});points.insert({1, 3});
// 或使用lambda(C++11)auto cmp = [](const Point& a, const Point& b) { if(a.x != b.x) return a.x < b.x; return a.y < b.y;};set<Point, decltype(cmp)> points2(cmp);有序键值对容器,按key自动排序,基于红黑树实现,时间复杂度O(log n)。
xxxxxxxxxxusing namespace std;
map<int, int> mp;
// 插入mp[key] = value;mp.insert({key, value});mp.insert(make_pair(key, value));
// 查找if(mp.find(key) != mp.end()) { int val = mp[key];}
if(mp.count(key)) { // 返回0或1 // 存在}
// 访问(不存在会自动创建)int val = mp[key];
// 删除mp.erase(key);mp.erase(it);
// 遍历(按key有序)for(auto& p : mp) { cout << p.first << " " << p.second << endl;}
for(auto& [k, v] : mp) { // C++17 cout << k << " " << v << endl;}
// 常用操作mp.size();mp.empty();mp.clear();
// multimap(允许重复key)multimap<int, int> mmp;需要按key排序
需要范围查询(lower_bound/upper_bound)
需要维护键值对映射关系
比unordered_map更稳定(最坏情况也是O(log n))
xxxxxxxxxxmap<int, int> mp;
// ❌ 陷阱:访问不存在的key会自动创建int val = mp[100]; // mp[100]被创建,值为0cout << mp.size() << endl; // 1
// ✅ 正确:先判断是否存在if(mp.find(100) != mp.end()) { int val = mp[100];} else { cout << "不存在" << endl;}
// 或使用countif(mp.count(100)) { int val = mp[100];}
// 统计频率时的常见用法(利用自动创建)vector<int> arr = {1, 2, 2, 3, 3, 3};map<int, int> freq;for(int x : arr) { freq[x]++; // 不存在时自动创建为0,然后++}xxxxxxxxxxmap<int, string> mp = {{1, "one"}, {2, "two"}};
// []:会自动创建,修改mapstring s1 = mp[3]; // 创建mp[3]=""cout << mp.size() << endl; // 3
// find:不会修改map,返回迭代器auto it = mp.find(4);if(it != mp.end()) { cout << it->second << endl;}cout << mp.size() << endl; // 还是3
// count:不会修改map,返回0或1if(mp.count(5)) { cout << "存在" << endl;}cout << mp.size() << endl; // 还是3
// 性能:find和count都是O(log n),但find更灵活xxxxxxxxxxmap<int, int> mp = {{1, 10}, {2, 20}, {3, 30}};
// ❌ 错误:遍历时删除for(auto& p : mp) { if(p.second > 15) { mp.erase(p.first); // 迭代器失效! }}
// ✅ 正确:使用迭代器for(auto it = mp.begin(); it != mp.end(); ) { if(it->second > 15) { it = mp.erase(it); // C++11返回下一个迭代器 } else { it++; }}
// ✅ 或先收集要删除的keyvector<int> toDelete;for(auto& p : mp) { if(p.second > 15) { toDelete.push_back(p.first); }}for(int key : toDelete) { mp.erase(key);}xxxxxxxxxxmap<int, string> mp = {{1, "a"}, {3, "c"}, {5, "e"}, {7, "g"}};
// lower_bound:第一个key>=x的元素auto it1 = mp.lower_bound(3);cout << it1->first << " " << it1->second << endl; // 3 c
auto it2 = mp.lower_bound(4);cout << it2->first << " " << it2->second << endl; // 5 e
// upper_bound:第一个key>x的元素auto it3 = mp.upper_bound(3);cout << it3->first << " " << it3->second << endl; // 5 e
// 查找范围auto it_start = mp.lower_bound(2);auto it_end = mp.upper_bound(6);for(auto it = it_start; it != it_end; it++) { cout << it->first << " "; // 3 5}xxxxxxxxxx// 使用pair作为keymap<pair<int, int>, string> mp;mp[{1, 2}] = "point";mp[{1, 3}] = "another";
// 自定义结构体作为key(必须定义operator<)struct Point { int x, y; bool operator < (const Point& other) const { if(x != other.x) return x < other.x; return y < other.y; }};
map<Point, int> pointMap;pointMap[{1, 2}] = 10;
// 或使用自定义比较函数auto cmp = [](const Point& a, const Point& b) { if(a.x != b.x) return a.x < b.x; return a.y < b.y;};map<Point, int, decltype(cmp)> pointMap2(cmp);xxxxxxxxxxmap<int, string> mp = {{1, "a"}, {2, "b"}, {3, "c"}};
// 第一个元素(key最小)auto first = mp.begin();cout << first->first << " " << first->second << endl; // 1 a
// 最后一个元素(key最大)auto last = prev(mp.end()); // 或 mp.rbegin()cout << last->first << " " << last->second << endl; // 3 c
// ❌ 错误:空mapmap<int, string> empty;// auto first = empty.begin(); // 可以,但不能解引用// cout << first->first; // 未定义行为!
// ✅ 正确:先判断if(!empty.empty()) { auto first = empty.begin(); cout << first->first << endl;}xxxxxxxxxxmultimap<int, string> mmp;mmp.insert({1, "a"});mmp.insert({1, "b"});mmp.insert({2, "c"});
// 统计某个key的个数int count = mmp.count(1); // 2
// 获取某个key的所有valueauto range = mmp.equal_range(1);for(auto it = range.first; it != range.second; it++) { cout << it->second << " "; // a b}
// multimap不支持[]操作符// mmp[1] = "x"; // 编译错误!
// 删除某个key的所有元素mmp.erase(1); // 删除所有key为1的元素
// 只删除一个auto it = mmp.find(2);if(it != mmp.end()) { mmp.erase(it);}无序键值对容器,基于哈希表实现,平均时间复杂度O(1),最坏O(n)。
xxxxxxxxxxusing namespace std;
unordered_map<int, int> mp;
// 插入mp[key] = value;mp.insert({key, value});
// 查找if(mp.find(key) != mp.end()) { int val = mp[key];}
if(mp.count(key)) { // 存在}
// 删除mp.erase(key);
// 遍历(无序)for(auto& p : mp) { cout << p.first << " " << p.second << endl;}
for(auto& [k, v] : mp) { // C++17 cout << k << " " << v << endl;}
// 常用操作mp.size();mp.empty();mp.clear();O(1)平均时间复杂度的查找、插入、删除
不需要排序
解决"两数之和"等哈希表经典问题
比map更快(不需要维护顺序)
xxxxxxxxxxunordered_map<int, int> mp;
// ❌ 陷阱:访问不存在的key会自动创建int val = mp[100]; // mp[100]被创建,值为0cout << mp.size() << endl; // 1
// ✅ 正确:先判断if(mp.find(100) != mp.end()) { int val = mp[100];}xxxxxxxxxxunordered_map<int, int> mp = {{1, 10}, {2, 20}, {3, 30}};
// ❌ 错误:unordered_map没有lower_bound// auto it = mp.lower_bound(2); // 编译错误!
// 如果需要范围查询,使用mapmap<int, int> ordered_mp = {{1, 10}, {2, 20}, {3, 30}};auto it = ordered_mp.lower_bound(2); // 正确xxxxxxxxxx// ❌ 错误:pair没有默认哈希函数// unordered_map<pair<int, int>, int> mp; // 编译错误!
// ✅ 正确:自定义哈希函数struct PairHash { size_t operator()(const pair<int, int>& p) const { return hash<int>()(p.first) ^ (hash<int>()(p.second) << 1); }};
unordered_map<pair<int, int>, int, PairHash> mp;mp[{1, 2}] = 10;
// 自定义结构体struct Point { int x, y; bool operator == (const Point& other) const { return x == other.x && y == other.y; }};
struct PointHash { size_t operator()(const Point& p) const { return hash<int>()(p.x) ^ (hash<int>()(p.y) << 1); }};
unordered_map<Point, int, PointHash> pointMap;xxxxxxxxxx// 最坏情况:所有key哈希到同一个桶,退化为O(n)unordered_map<int, int> mp;
// 恶意数据可能导致哈希冲突// 解决方案1:使用map(稳定O(log n))map<int, int> safe_mp;
// 解决方案2:自定义哈希函数struct CustomHash { size_t operator()(int x) const { // 使用随机种子 static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count(); return hash<int>()(x) ^ FIXED_RANDOM; }};
unordered_map<int, int, CustomHash> mp_safe;xxxxxxxxxxunordered_map<int, int> mp = {{1, 10}, {2, 20}, {3, 30}};
// 遍历顺序不确定,每次可能不同for(auto& p : mp) { cout << p.first << " "; // 可能是 3 1 2 或其他顺序}
// 如果需要有序遍历,使用map或先排序vector<pair<int, int>> vec(mp.begin(), mp.end());sort(vec.begin(), vec.end());for(auto& p : vec) { cout << p.first << " "; // 1 2 3}xxxxxxxxxxvector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> mp; // 值 -> 下标 for(int i = 0; i < nums.size(); i++) { int complement = target - nums[i]; if(mp.find(complement) != mp.end()) { return {mp[complement], i}; } mp[nums[i]] = i; } return {};}xxxxxxxxxxvector<int> arr = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4};
// 方法1:利用[]自动创建unordered_map<int, int> freq;for(int x : arr) { freq[x]++;}
// 方法2:使用insertunordered_map<int, int> freq2;for(int x : arr) { auto it = freq2.find(x); if(it != freq2.end()) { it->second++; } else { freq2[x] = 1; }}
// 找出现次数最多的元素int maxFreq = 0, maxElem = 0;for(auto& p : freq) { if(p.second > maxFreq) { maxFreq = p.second; maxElem = p.first; }}无序集合,基于哈希表实现,自动去重,平均时间复杂度O(1)。
xxxxxxxxxxusing namespace std;
unordered_set<int> st;
st.insert(x); // 插入st.erase(x); // 删除st.count(x); // 是否存在(返回0或1)st.find(x) != st.end(); // 是否存在st.size();st.empty();st.clear();
// 遍历(无序)for(int x : st) { cout << x << " ";}O(1)平均时间复杂度的查找、插入、删除
快速去重
快速判断元素是否存在
比set更快(不需要维护顺序)
xxxxxxxxxxunordered_set<int> st = {1, 3, 5, 7, 9};
// ❌ 错误:unordered_set没有lower_bound// auto it = st.lower_bound(5); // 编译错误!
// 如果需要有序操作,使用setset<int> ordered_st = {1, 3, 5, 7, 9};auto it = ordered_st.lower_bound(5); // 正确xxxxxxxxxxunordered_set<int> st = {1, 2, 3, 4, 5};
// 遍历顺序不确定for(int x : st) { cout << x << " "; // 可能是 3 1 5 2 4 或其他顺序}
// 如果需要有序遍历,转为vector后排序vector<int> vec(st.begin(), st.end());sort(vec.begin(), vec.end());for(int x : vec) { cout << x << " "; // 1 2 3 4 5}xxxxxxxxxxvector<int> arr = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4};
// 方法1:使用unordered_setunordered_set<int> st(arr.begin(), arr.end());vector<int> unique_arr(st.begin(), st.end());
// 方法2:使用set(有序)set<int> ordered_st(arr.begin(), arr.end());vector<int> unique_sorted(ordered_st.begin(), ordered_st.end());
// 方法3:sort + unique(原地去重)sort(arr.begin(), arr.end());arr.erase(unique(arr.begin(), arr.end()), arr.end());xxxxxxxxxxbool hasDuplicate(vector<int>& nums) { unordered_set<int> st; for(int x : nums) { if(st.count(x)) { return true; // 找到重复 } st.insert(x); } return false;}
// 或者更简洁bool hasDuplicate2(vector<int>& nums) { unordered_set<int> st(nums.begin(), nums.end()); return st.size() != nums.size();}xxxxxxxxxx// ❌ 错误:pair没有默认哈希函数// unordered_set<pair<int, int>> st; // 编译错误!
// ✅ 正确:自定义哈希函数struct PairHash { size_t operator()(const pair<int, int>& p) const { return hash<int>()(p.first) ^ (hash<int>()(p.second) << 1); }};
unordered_set<pair<int, int>, PairHash> st;st.insert({1, 2});xxxxxxxxxxunordered_set<int> st1 = {1, 2, 3, 4, 5};unordered_set<int> st2 = {3, 4, 5, 6, 7};
// 交集unordered_set<int> intersection;for(int x : st1) { if(st2.count(x)) { intersection.insert(x); }}
// 并集unordered_set<int> union_set = st1;for(int x : st2) { union_set.insert(x);}
// 差集(st1 - st2)unordered_set<int> difference;for(int x : st1) { if(!st2.count(x)) { difference.insert(x); }}
// 使用STL算法(需要set)set<int> s1 = {1, 2, 3, 4, 5};set<int> s2 = {3, 4, 5, 6, 7};vector<int> result;
// 交集set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), back_inserter(result));
// 并集set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), back_inserter(result));
// 差集set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), back_inserter(result));提供通用工具,最常用的是pair(对组)和swap(交换)。
xxxxxxxxxxusing namespace std;
// pairpair<int, int> p;p = make_pair(1, 2);p = {1, 2}; // C++11
// 访问p.first;p.second;
// 比较(先比first,再比second)pair<int, int> p1 = {1, 2};pair<int, int> p2 = {1, 3};p1 < p2; // true
// swapint a = 1, b = 2;swap(a, b); // a=2, b=1
vector<int> v1 = {1, 2, 3};vector<int> v2 = {4, 5, 6};swap(v1, v2); // 交换两个vectorpair:存储坐标、键值对、需要同时返回两个值
swap:交换变量,比手写更高效(容器的swap是O(1))
xxxxxxxxxxpair<int, int> p1 = {1, 3};pair<int, int> p2 = {2, 1};pair<int, int> p3 = {1, 2};
// 先比first,first相同再比secondp1 < p2; // true(1 < 2)p1 < p3; // false(first相同,3 > 2)p3 < p1; // true(first相同,2 < 3)
// 排序pair数组vector<pair<int, int>> v = {{2, 1}, {1, 3}, {1, 2}};sort(v.begin(), v.end());// 结果:{1, 2}, {1, 3}, {2, 1}xxxxxxxxxxvector<pair<int, int>> v = {{1, 3}, {2, 1}, {1, 2}};
// 按second排序sort(v.begin(), v.end(), [](auto& a, auto& b) { return a.second < b.second;});// 结果:{2, 1}, {1, 2}, {1, 3}
// 按first降序,second升序sort(v.begin(), v.end(), [](auto& a, auto& b) { if(a.first != b.first) return a.first > b.first; return a.second < b.second;});// 结果:{2, 1}, {1, 2}, {1, 3}xxxxxxxxxx// pair可以直接作为map的keymap<pair<int, int>, int> mp;mp[{1, 2}] = 10;mp[{1, 3}] = 20;
// 但不能直接作为unordered_map的key(需要自定义哈希)// unordered_map<pair<int, int>, int> ump; // 编译错误!
struct PairHash { size_t operator()(const pair<int, int>& p) const { return hash<int>()(p.first) ^ (hash<int>()(p.second) << 1); }};
unordered_map<pair<int, int>, int, PairHash> ump;ump[{1, 2}] = 10;xxxxxxxxxx// 对于基本类型,swap和手写差不多int a = 1, b = 2;swap(a, b); // 等价于 int temp = a; a = b; b = temp;
// 对于容器,swap是O(1)(只交换指针)vector<int> v1(1000000, 1);vector<int> v2(1000000, 2);
// ❌ 低效:O(n)vector<int> temp = v1;v1 = v2;v2 = temp;
// ✅ 高效:O(1)swap(v1, v2);
// 也可以用成员函数v1.swap(v2);xxxxxxxxxx// 函数返回两个值pair<int, int> divmod(int a, int b) { return {a / b, a % b}; // C++11 // 或 return make_pair(a / b, a % b);}
auto result = divmod(10, 3);cout << "商:" << result.first << " 余数:" << result.second << endl;
// C++17:结构化绑定auto [quotient, remainder] = divmod(10, 3);cout << "商:" << quotient << " 余数:" << remainder << endl;xxxxxxxxxx// pair嵌套pair<int, pair<int, int>> p = {1, {2, 3}};cout << p.first << " " << p.second.first << " " << p.second.second << endl;
// 但这样可读性差,建议用结构体struct Point3D { int x, y, z;};
Point3D p3d = {1, 2, 3};cout << p3d.x << " " << p3d.y << " " << p3d.z << endl;提供数值计算相关的算法,如求和、最大公约数等。
xxxxxxxxxxusing namespace std;
vector<int> v = {1, 2, 3, 4, 5};
// 求和int sum = accumulate(v.begin(), v.end(), 0); // 15
// 求积int product = accumulate(v.begin(), v.end(), 1, multiplies<int>());
// 最大公约数(C++17)int g = gcd(12, 18); // 6
// 最小公倍数(C++17)int l = lcm(12, 18); // 36
// 部分和(前缀和)vector<int> prefix(v.size());partial_sum(v.begin(), v.end(), prefix.begin());// prefix = {1, 3, 6, 10, 15}
// 相邻差分vector<int> diff(v.size());adjacent_difference(v.begin(), v.end(), diff.begin());// diff = {1, 1, 1, 1, 1}
// 内积vector<int> v2 = {1, 2, 3, 4, 5};int dot = inner_product(v.begin(), v.end(), v2.begin(), 0);// 1*1 + 2*2 + 3*3 + 4*4 + 5*5 = 55
// iota:填充递增序列vector<int> seq(10);iota(seq.begin(), seq.end(), 1);// seq = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}accumulate:快速求和,避免手写循环
gcd/lcm:数论问题必备
partial_sum:快速计算前缀和
iota:快速生成递增序列
xxxxxxxxxxvector<int> v = {1, 2, 3, 4, 5};
// ❌ 错误:初始值是int,可能溢出int sum = accumulate(v.begin(), v.end(), 0);
// ✅ 正确:初始值是long longlong long sum = accumulate(v.begin(), v.end(), 0LL);
// 浮点数求和vector<double> vd = {1.1, 2.2, 3.3};double sum_d = accumulate(vd.begin(), vd.end(), 0.0); // 注意是0.0xxxxxxxxxxvector<int> v = {1, 2, 3, 4, 5};
// 求积int product = accumulate(v.begin(), v.end(), 1, [](int a, int b) { return a * b;});
// 求最大值int maxVal = accumulate(v.begin(), v.end(), INT_MIN, [](int a, int b) { return max(a, b);});
// 拼接字符串vector<string> words = {"hello", " ", "world"};string sentence = accumulate(words.begin(), words.end(), string(""));// "hello world"xxxxxxxxxx// gcd:最大公约数int g = gcd(12, 18); // 6int g2 = gcd(0, 5); // 5(特殊情况)int g3 = gcd(0, 0); // 0
// lcm:最小公倍数int l = lcm(12, 18); // 36
// ❌ 错误:lcm可能溢出int l2 = lcm(1000000, 999999); // 可能溢出
// ✅ 正确:使用long longlong long l3 = lcm(1000000LL, 999999LL);
// 手写gcd(辗转相除法)int gcd_manual(int a, int b) { return b == 0 ? a : gcd_manual(b, a % b);}
// 手写lcmint lcm_manual(int a, int b) { return a / gcd_manual(a, b) * b; // 先除后乘,防止溢出}xxxxxxxxxxvector<int> v = {1, 2, 3, 4, 5};vector<int> prefix(v.size());
// 计算前缀和partial_sum(v.begin(), v.end(), prefix.begin());// prefix = {1, 3, 6, 10, 15}
// 可以原地计算partial_sum(v.begin(), v.end(), v.begin());// v = {1, 3, 6, 10, 15}
// 自定义操作(前缀积)vector<int> v2 = {1, 2, 3, 4, 5};partial_sum(v2.begin(), v2.end(), v2.begin(), multiplies<int>());// v2 = {1, 2, 6, 24, 120}xxxxxxxxxx// 生成1到nvector<int> seq(10);iota(seq.begin(), seq.end(), 1);// seq = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 生成0到n-1vector<int> indices(5);iota(indices.begin(), indices.end(), 0);// indices = {0, 1, 2, 3, 4}
// 用于初始化下标数组vector<int> idx(n);iota(idx.begin(), idx.end(), 0);sort(idx.begin(), idx.end(), [&](int i, int j) { return arr[i] < arr[j]; // 按arr的值排序下标});C风格字符串处理函数,主要用于char数组操作。
xxxxxxxxxxusing namespace std;
char s1[100] = "hello";char s2[100] = "world";
// 长度int len = strlen(s1); // 5
// 复制strcpy(s1, s2); // s1 = "world"
// 拼接strcat(s1, s2); // s1 = s1 + s2
// 比较int cmp = strcmp(s1, s2); // <0: s1<s2, =0: s1==s2, >0: s1>s2
// 查找字符char* p = strchr(s1, 'l'); // 找第一个'l'
// 查找子串char* p2 = strstr(s1, "ll"); // 找子串"ll"
// 内存操作memset(s1, 0, sizeof(s1)); // 全部设为0memcpy(s1, s2, strlen(s2)); // 复制内存竞赛中有时需要用char数组
memset快速初始化数组
某些题目要求使用C风格字符串
xxxxxxxxxxchar s[] = "hello";cout << strlen(s) << endl; // 5cout << sizeof(s) << endl; // 6(包括'\0')
// ❌ 错误:未初始化的数组char s2[100];int len = strlen(s2); // 未定义行为!
// ✅ 正确:先初始化char s3[100] = {0}; // 或 memset(s3, 0, sizeof(s3));int len = strlen(s3); // 0xxxxxxxxxxchar s1[10] = "hello";char s2[100] = "world";
// ❌ 危险:可能越界strcpy(s1, s2); // s1只有10字节,可能溢出
// ✅ 安全:使用strncpystrncpy(s1, s2, sizeof(s1) - 1);s1[sizeof(s1) - 1] = '\0'; // 确保以'\0'结尾
// strcat也有同样问题char s3[10] = "hi";// strcat(s3, "verylongstring"); // 危险!
// 使用strncatstrncat(s3, "verylongstring", sizeof(s3) - strlen(s3) - 1);xxxxxxxxxxchar s1[] = "abc";char s2[] = "abd";char s3[] = "abc";
// strcmp返回值:<0, 0, >0int cmp1 = strcmp(s1, s2); // <0(s1 < s2)int cmp2 = strcmp(s1, s3); // 0(s1 == s3)int cmp3 = strcmp(s2, s1); // >0(s2 > s1)
// ❌ 错误:不能用==比较// if(strcmp(s1, s2) == true) { // 错误!
// ✅ 正确if(strcmp(s1, s3) == 0) { cout << "相等" << endl;}xxxxxxxxxxint arr[100];
// ✅ 正确:设置为0memset(arr, 0, sizeof(arr));
// ✅ 正确:设置为-1(全1)memset(arr, -1, sizeof(arr));
// ❌ 错误:设置为其他值(如1)memset(arr, 1, sizeof(arr)); // 结果不是全1!// memset按字节设置,arr[0]会是0x01010101(16843009)
// ✅ 正确:用fill或循环fill(arr, arr + 100, 1);
// 或for(int i = 0; i < 100; i++) { arr[i] = 1;}xxxxxxxxxxint arr[100];
// ❌ 错误:忘记sizeofmemset(arr, 0, 100); // 只清零了25个int(100字节)
// ✅ 正确memset(arr, 0, sizeof(arr)); // 清零100个int(400字节)
// 对于vector,不能用memsetvector<int> v(100);// memset(&v[0], 0, v.size()); // 错误!应该用sizeof(int) * v.size()memset(&v[0], 0, sizeof(int) * v.size()); // 正确
// 但更推荐用fillfill(v.begin(), v.end(), 0);xxxxxxxxxx// C字符串char s1[] = "hello";int len1 = strlen(s1);char s2[100];strcpy(s2, s1);
// C++字符串(推荐)string s3 = "hello";int len2 = s3.length();string s4 = s3;
// 转换// C++ string -> C字符串const char* cstr = s3.c_str();
// C字符串 -> C++ stringstring s5(s1);string s6 = string(s1);定义各种数据类型的最大最小值常量。
xxxxxxxxxxusing namespace std;
// 整数类型INT_MAX // int最大值:2147483647INT_MIN // int最小值:-2147483648UINT_MAX // unsigned int最大值
LONG_MAX // long最大值LONG_MIN // long最小值
LLONG_MAX // long long最大值:9223372036854775807LLONG_MIN // long long最小值:-9223372036854775808
CHAR_MAX // char最大值:127CHAR_MIN // char最小值:-128
SHRT_MAX // short最大值SHRT_MIN // short最小值初始化最大最小值
判断溢出
边界条件处理
xxxxxxxxxx// 找最小值int minVal = INT_MAX;for(int x : arr) { minVal = min(minVal, x);}
// 找最大值int maxVal = INT_MIN;for(int x : arr) { maxVal = max(maxVal, x);}
// ❌ 错误:用0初始化int minVal = 0; // 如果所有元素都>0,结果错误
// ❌ 错误:用-1初始化int maxVal = -1; // 如果所有元素都<-1,结果错误xxxxxxxxxxint a = INT_MAX;int b = 1;
// ❌ 错误:溢出int sum = a + b; // 溢出,变成负数
// ✅ 正确:先判断if(a > INT_MAX - b) { cout << "会溢出" << endl;} else { int sum = a + b;}
// 或使用long longlong long sum = (long long)a + b;xxxxxxxxxxint x = INT_MIN;
// ❌ 错误:-INT_MIN还是INT_MIN(溢出)int y = -x; // 还是-2147483648
// abs(INT_MIN)也会溢出int z = abs(INT_MIN); // 未定义行为
// ✅ 正确:使用long longlong long y = -(long long)x; // 2147483648xxxxxxxxxx// 用INT_MAX表示无穷大const int INF = INT_MAX;
// 但要注意加法溢出int dist = INF;int edge = 10;int newDist = dist + edge; // 溢出!
// ✅ 正确:使用较小的INFconst int INF = 0x3f3f3f3f; // 1061109567// 优点:// 1. 两个INF相加不溢出// 2. memset(arr, 0x3f, sizeof(arr))可以初始化为INFxxxxxxxxxx
DBL_MAX // double最大值DBL_MIN // double最小正值(不是最小值!)-DBL_MAX // double最小值
FLT_MAX // float最大值FLT_MIN // float最小正值
// 无穷大double inf = INFINITY;double neg_inf = -INFINITY;
// 判断isinf(inf); // trueisfinite(inf); // false固定大小的位数组,支持位运算,比bool数组更节省空间。
xxxxxxxxxxusing namespace std;
// 声明(大小必须是编译期常量)bitset<8> bs; // 8位,全0bitset<8> bs(10); // 二进制:00001010bitset<8> bs("1010"); // 从字符串构造
// 基本操作bs.set(); // 全部设为1bs.set(i); // 第i位设为1bs.set(i, val); // 第i位设为valbs.reset(); // 全部设为0bs.reset(i); // 第i位设为0bs.flip(); // 全部翻转bs.flip(i); // 第i位翻转
// 访问bs[i]; // 访问第i位bs.test(i); // 测试第i位是否为1
// 查询bs.count(); // 1的个数bs.size(); // 总位数bs.any(); // 是否有1bs.none(); // 是否全0bs.all(); // 是否全1
// 转换bs.to_ulong(); // 转为unsigned longbs.to_ullong(); // 转为unsigned long longbs.to_string(); // 转为字符串
// 位运算bitset<8> bs1("1010");bitset<8> bs2("1100");bs1 & bs2; // 按位与:1000bs1 | bs2; // 按位或:1110bs1 ^ bs2; // 按位异或:0110~bs1; // 按位取反:0101bs1 << 2; // 左移:101000bs1 >> 2; // 右移:0010节省空间(1位存储1个bool,而bool通常占1字节)
快速位运算
状态压缩DP
集合运算
xxxxxxxxxxint n = 100;// ❌ 错误:n不是编译期常量// bitset<n> bs; // 编译错误!
// ✅ 正确:使用常量const int N = 100;bitset<N> bs;
// 或使用宏bitset<MAX_N> bs2;
// 如果需要运行时确定大小,使用vector<bool>vector<bool> vb(n);xxxxxxxxxxbitset<8> bs("1010");
// 位的顺序:从右到左// 字符串"1010"表示:// 索引: 7 6 5 4 3 2 1 0// 值: 0 0 0 0 1 0 1 0
cout << bs[0] << endl; // 0(最右边)cout << bs[1] << endl; // 1cout << bs[2] << endl; // 0cout << bs[3] << endl; // 1(最左边)
// 输出时从左到右cout << bs << endl; // 00001010xxxxxxxxxxbitset<64> bs;bs.set(); // 全1
// ❌ 错误:超过unsigned long范围(32位系统)// unsigned long val = bs.to_ulong(); // 可能溢出
// ✅ 正确:使用to_ullongunsigned long long val = bs.to_ullong();
// 检查是否会溢出bitset<100> large_bs;large_bs.set();// large_bs.to_ullong(); // 溢出!超过64位
// 只能用字符串string s = large_bs.to_string();xxxxxxxxxxbitset<8> bs1("1010");bitset<8> bs2("1100");
// ❌ 错误:优先级问题// if(bs1 & bs2 == bitset<8>("1000")) { // 错误!
// ✅ 正确:加括号if((bs1 & bs2) == bitset<8>("1000")) { cout << "相等" << endl;}xxxxxxxxxx// 旅行商问题(TSP)int n = 4; // 4个城市int dist[4][4]; // 距离矩阵
// dp[mask][i]:访问过的城市集合为mask,当前在城市i的最短路径vector<vector<int>> dp(1 << n, vector<int>(n, INT_MAX));
// mask用bitset表示for(int mask = 0; mask < (1 << n); mask++) { bitset<4> bs(mask); // 检查城市i是否被访问过 for(int i = 0; i < n; i++) { if(bs[i]) { // 城市i已访问 } }}
// 添加城市i到集合int mask = 0;bitset<4> bs(mask);bs.set(2); // 访问城市2mask = bs.to_ulong();
// 移除城市ibs.reset(2);mask = bs.to_ulong();xxxxxxxxxxbitset<8> set1("10101010");bitset<8> set2("11001100");
// 交集bitset<8> intersection = set1 & set2; // 10001000
// 并集bitset<8> union_set = set1 | set2; // 11101110
// 差集(set1 - set2)bitset<8> difference = set1 & (~set2); // 00100010
// 对称差(异或)bitset<8> sym_diff = set1 ^ set2; // 01100110
// 判断是否为子集bool is_subset = ((set1 & set2) == set1);xxxxxxxxxxbitset<32> bs(12345);
// count():统计1的个数int ones = bs.count();
// 比手写循环快int count_manual = 0;for(int i = 0; i < 32; i++) { if(bs[i]) count_manual++;}
// 也可以用__builtin_popcountint count_builtin = __builtin_popcount(12345);xxxxxxxxxx// 1. 判断奇偶性bitset<32> bs(n);bool is_odd = bs[0]; // 最低位为1则为奇数
// 2. 乘以2的幂bitset<32> bs(n);bs <<= k; // n * 2^kint result = bs.to_ulong();
// 3. 除以2的幂bs >>= k; // n / 2^kresult = bs.to_ulong();
// 4. 判断是否为2的幂bitset<32> bs(n);bool is_power_of_2 = (bs.count() == 1);
// 5. 获取最低位的1bitset<32> bs(n);int lowest_bit = (bs & (-bs)).to_ulong();xxxxxxxxxx
char c = 'a';
// 判断isalpha(c); // 是否为字母isdigit(c); // 是否为数字isalnum(c); // 是否为字母或数字islower(c); // 是否为小写isupper(c); // 是否为大写isspace(c); // 是否为空白字符(空格、\t、\n等)ispunct(c); // 是否为标点符号
// 转换tolower(c); // 转小写toupper(c); // 转大写
// 常见用法string s = "Hello World";for(char& c : s) { c = tolower(c);}cout << s << endl; // "hello world"
// 统计字母数字int count = 0;for(char c : s) { if(isalnum(c)) count++;}xxxxxxxxxx
// 浮点数范围DBL_MAX // double最大值:1.7976931348623157e+308DBL_MIN // double最小正值:2.2250738585072014e-308DBL_EPSILON // double精度:2.2204460492503131e-16
FLT_MAX // float最大值FLT_MIN // float最小正值FLT_EPSILON // float精度
// 使用场景const double EPS = 1e-9; // 或 DBL_EPSILON
bool equal(double a, double b) { return fabs(a - b) < EPS;}xxxxxxxxxx
// 随机数srand(time(0)); // 设置随机种子int r = rand(); // 生成随机数[0, RAND_MAX]int r2 = rand() % 100; // [0, 99]int r3 = rand() % 100 + 1; // [1, 100]
// 绝对值int a = abs(-5); // 5long b = labs(-5L); // 5long long c = llabs(-5LL); // 5
// 字符串转数字(C风格)int n = atoi("123");long l = atol("123456789");long long ll = atoll("123456789012345");double d = atof("3.14");
// 退出程序exit(0); // 正常退出exit(1); // 异常退出xxxxxxxxxx
// 计时auto start = chrono::high_resolution_clock::now();
// ... 代码 ...
auto end = chrono::high_resolution_clock::now();auto duration = chrono::duration_cast<chrono::milliseconds>(end - start);cout << "耗时:" << duration.count() << "ms" << endl;
// 随机种子(更好的方法)unsigned seed = chrono::system_clock::now().time_since_epoch().count();srand(seed);xxxxxxxxxx
// 更好的随机数生成random_device rd;mt19937 gen(rd()); // Mersenne Twister引擎
// 均匀分布[1, 100]uniform_int_distribution<> dis(1, 100);int r = dis(gen);
// 均匀实数分布[0.0, 1.0)uniform_real_distribution<> dis_real(0.0, 1.0);double r2 = dis_real(gen);
// 正态分布normal_distribution<> dis_normal(0.0, 1.0); // 均值0,标准差1double r3 = dis_normal(gen);
// 打乱数组vector<int> v = {1, 2, 3, 4, 5};shuffle(v.begin(), v.end(), gen);输入输出
<iostream> - cin/cout(推荐)
<cstdio> - scanf/printf(更快)
<iomanip> - 格式化输出
容器
<vector> - 动态数组(最常用)
<string> - 字符串
<array> - 固定大小数组(C++11)
<deque> - 双端队列
关联容器
<map> - 有序映射(O(log n))
<set> - 有序集合(O(log n))
<unordered_map> - 哈希表(O(1)平均)
<unordered_set> - 哈希集合(O(1)平均)
适配器
<stack> - 栈
<queue> - 队列、优先队列
算法
<algorithm> - 排序、查找、反转等(必备)
<numeric> - 数值算法(求和、GCD等)
数学
<cmath> - 数学函数
<climits> - 常量限制
<cfloat> - 浮点数限制
其他
<utility> - pair、swap
<cstring> - C字符串、memset
<bitset> - 位集合
<cctype> - 字符处理
<random> - 随机数(C++11)
| 操作 | vector | deque | list | set | unordered_set |
|---|---|---|---|---|---|
| 随机访问 | O(1) | O(1) | O(n) | O(log n) | - |
| 头部插入 | O(n) | O(1) | O(1) | O(log n) | O(1)平均 |
| 尾部插入 | O(1) | O(1) | O(1) | O(log n) | O(1)平均 |
| 中间插入 | O(n) | O(n) | O(1) | O(log n) | O(1)平均 |
| 查找 | O(n) | O(n) | O(n) | O(log n) | O(1)平均 |
| 排序 | 支持 | 支持 | 支持 | 自动 | 不支持 |
需要动态数组 → vector
需要频繁头尾操作 → deque
需要快速查找 → unordered_set / unordered_map
需要有序 → set / map
需要栈 → stack
需要队列 → queue
需要优先队列 → priority_queue
需要位运算 → bitset
熟练掌握STL:vector、map、set、queue、stack是基础
理解时间复杂度:知道什么时候用什么容器
注意边界条件:空容器、单元素、越界、溢出
善用algorithm:sort、binary_search、lower_bound等
避免常见陷阱:
vector的size()是无符号数
map的[]会自动创建元素
pop()没有返回值
迭代器失效
memset只能设置0或-1
加速IO:大数据量时使用ios::sync_with_stdio(false)
使用万能头:竞赛时用#include <bits/stdc++.h>
虽然 Dev-C++ 原生支持 <bits/stdc++.h> 万能头,但国内大部分考场(如机试、CSP、蓝桥杯等)提供的往往是古董级的 Dev-C++ 5.11 版本。
这个版本默认采用的是 C++98 标准。如果不做任何设置,你在平时刷题时习以为常的现代语法都会直接引发编译报错(Compile Error),例如:
auto 自动类型推导 ❌
基于范围的 for (int x : vec) 循环 ❌
unordered_map / unordered_set 哈希容器 ❌
列表初始化 vector<int> v = {1, 2, 3}; ❌
✅ 坐下后的第一件事:开启 C++11 支持
为了在考场上能正常使用现代 C++ 的便利特性,请在敲第一行代码前,严格按照以下步骤配置你的 Dev-C++:
在顶部菜单栏点击 工具 (Tools) -> 编译选项 (Compiler Options)。
在弹出的窗口中,勾选 编译时加入以下命令 (Add the following commands when calling the compiler)。
在下方的输入框中,准确地填入以下命令(注意全是小写,没有空格):
-std=c++11
点击 确定。
配置完成后,配合万能头文件,你的 Dev-C++ 才是真正意义上的考场“完全体”。
如果由于客观限制无法开启 C++11,编译器会退化到 C++98 标准。为了防止在考场上因为语法报错而心态崩溃,请务必牢记以下 5 个“语法退化”替换方案:
在 C++98 中,连续的两个右尖括号 >> 会被编译器直接解析为“右移位运算符”,从而引发莫名其妙的语法错误。
❌ 报错写法: vector<vector<int>> 或 priority_queue<int, vector<int>, greater<int>>
✅ 正确写法: vector<vector<int> > (⚠️ 最后的两个尖括号之间必须敲一个空格!)
C++98 的标准库中没有哈希表(即 unordered_ 系列)。
❌ 报错写法: 使用 unordered_map 或 unordered_set。
✅ 替代方案: 只能无条件替换为基于红黑树的 map 和 set。
⚠️ 避坑提醒: 这意味着你的单次查询/插入时间复杂度会从 O(1) 降级为 O(log N)。虽然有超时的风险,但这已经是 C++98 环境下唯一的标准选择了。
auto 和 范围 for 循环现代 C++ 极其方便的类型推导和遍历方式在 C++98 中完全不存在。
❌ 报错写法: auto it = m.begin(); 或 for (int x : vec)
✅ 正确写法: 必须老老实实写全类型和下标:
遍历数组: for (int i = 0; i < vec.size(); i++)
遍历 Map: for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{} 列表初始化不能再直接给容器赋初值了。
❌ 报错写法: vector<int> v = {1, 2, 3};
✅ 正确写法: 老老实实使用 .push_back() 一个个塞进去,或者先建一个常规数组再拷贝:
xxxxxxxxxxint arr[] = {1, 2, 3};vector<int> v(arr, arr + 3); // 传入首尾指针进行初始化to_string() 和 stoi() 失效✅ 替代方案: * 数字转字符串: 使用 <sstream> 头文件里的 stringstream,或者使用 C 语言的 sprintf。
字符串转数字: 使用 C 语言的 sscanf,或者 atoi() / atof()。