① 程序设计基础 — 第 1 课(续)
vector 把数据装进了容器,读完 n 个数就能随便用。sort)和字符串(string),而且它们各有一个必背的坑。学完这一课,你手里就有一套「读入 → 排序 → 去重 → 输出」的完整套路。
sort(开始, 结束) 一行排序,结束位置是最后一个的下一个。sort,再 erase(unique(...), end())。string 就是字符版 vector,+ 拼接、size() 数长度。sort 在 <algorithm> 头文件里,底层是快排 + 堆排 + 插排的混合,复杂度 O(n log n)。你只需要记住三个用法:
#include <iostream>
#include <vector>
#include <algorithm> // sort 在这里
using namespace std;
int main() {
vector<int> v = {3, 1, 4, 1, 5, 9, 2};
sort(v.begin(), v.end()); // 升序:1 1 2 3 4 5 9
sort(v.rbegin(), v.rend()); // 降序:9 5 4 3 2 1 1
// 只排前 4 个
sort(v.begin(), v.begin() + 4); // v[0..3] 排序,其余不动
}
sort(开始位置, 结束位置)。结束位置是 最后一个元素的下一个位置(左闭右开)。排整个 vector 就是 v.begin() 到 v.end()。
这是竞赛中的经典组合。比如洛谷 P1059「明明的随机数」—— 输入 N 个数,排序去重后输出。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
sort(a.begin(), a.end()); // 1. 排好序
a.erase(unique(a.begin(), a.end()), a.end()); // 2. 去重
cout << a.size() << endl;
for (int x : a) cout << x << ' ';
return 0;
}
unique 只是把重复元素「挤」到末尾,返回新末尾的迭代器。erase。两行必须一起用,少一行就等于没去重。
string 本质上就是一个 vector<char>,再加上字符串专属操作。你会用 vector,就会用 string。
| 操作 | 代码 | 说明 |
|---|---|---|
| 读入 | cin >> s; | 读一个单词(遇空格/换行停) |
| 读整行 | getline(cin, s); | 读到换行(含空格) |
| 长度 | s.size() | 字符个数 |
| 取字符 | s[i] | 第 i 个字符,从 0 开始 |
| 追加 | s += "hello"; | 拼接到末尾 |
| 比较 | s == t s < t | 字典序比较 |
| 子串 | s.substr(i, len) | 从 i 开始取 len 个字符 |
| 查找 | s.find("abc") | 返回下标,找不到返回 string::npos |
string s;
cin >> s;
// 方法 1:手写循环
for (int i = s.size() - 1; i >= 0; i--) {
cout << s[i];
}
// 方法 2:STL 一键
reverse(s.begin(), s.end());
cout << s;
reverse 也在 <algorithm> 里,任何能用 begin() / end() 的容器都能反转。
sort(v.begin(), v.end()) 才对;写成 v.end() - 1 会把最后一个元素漏掉不排。unique 等于没去重:它只把重复的挤到后面,必须接 erase 才真的删掉。unique 只能挤掉相邻的重复元素,乱序的数组挤不干净。cin >> s 遇到空格就停:读带空格的一整行必须用 getline(cin, s)。find 找不到返回 string::npos:判断要写成 s.find(x) != string::npos,不要拿它当普通下标用。substr(i, len) 的第二个参数是长度,不是结束下标;substr(2, 3) 取的是下标 2、3、4 三个字符。sort(v.begin(), v.begin() + 3) 会排序几个元素?"apple" < "banana" 的结果是?cin >> s 读入 "hello world" 后,s 的值是?| 主题 | 题目 | 做法 |
|---|---|---|
| 排序 | 洛谷 P1059 · 明明的随机数 | 直接套用上面的排序 + 去重模版 |
| 字符串 | 洛谷 P1125 · 笨小猴 | 统计字母出现次数,找最大值和最小值(提示:用 vector<int>(26) 当计数器) |
卡住时的自查顺序
sort 的范围没写错。unique 的话,输出的个数还是原来那么多。getline(cin, s)。sort 一行排序:三个参数位置,左闭右开,升序降序换个迭代器就行。sort 先排好,再 erase(unique(...), end())。string 是字符版 vector:+ 拼接、size() 数长度、s[i] 取字符。find 找不到返回 string::npos,判断时和它比较,不要和下标混用。cin >> s,整行用 getline。long long、double、char、bool),把 if / else if / else 写顺,再学会把一段逻辑打包成函数。有了函数,后面那些「排序」「判断」就能反复调用,而不是每次重抄一遍。
unique 要配 erase、cin >> 遇空格停)会在后面反复出现,建议现在就把它们背下来。哪一句还不明白 —— 比如「unique 到底把重复元素挪到哪了」「string::npos 是什么值」「降序为什么用 rbegin」—— 直接问。