std::unique不能直接去重字符串,因为它只移除连续重复元素;对未排序字符串如"abac"无效,而"aabbcc"才变为"abc"。

std::unique 为什么不能直接去重字符串?
std::unique 不是“去重函数”,它只移除**连续重复元素**。对未排序的 std::string 直接调用 std::unique,只会删掉相邻的相同字符,比如 "abac" 变成 "abac"(没变),而 "aabbcc" 才会变成 "abc"。这是最常踩的坑——误以为它等价于 Python 的 set()。
std::sort + std::unique 组合的正确写法
必须先排序,再 unique,最后用 erase 真实收缩容器。对 std::string 操作时,注意它本质是 std::vector<char></char>,所以支持随机访问和迭代器操作:
std::string s = "hello world"; std::sort(s.begin(), s.end()); // 排序 → " dehllloorw" auto last = std::unique(s.begin(), s.end()); // 移除连续重复 → " delorw"(末尾残留) s.erase(last, s.end()); // 真实截断 → " delorw"
关键点:
-
std::unique返回的是新逻辑结尾的迭代器,不改变原容器大小 - 空格、大小写都会参与排序和去重,
"Hello"→'H','e','l','l','o'→ 去重后保留一个'l',但'H'和'h'被视为不同字符 - 若需忽略大小写,得自己写比较函数传给
std::sort,且std::unique也要配套用相同逻辑(否则行为不一致)
性能与适用边界:什么时候别用这招?
这个组合时间复杂度是 O(n log n)(主要花在 std::sort 上),空间 O(1)(原地)。但它只适合「保留字符出现顺序无关,且允许重排」的场景。比如统计字符种类数、生成字典序唯一字符集,没问题;但如果你要保持首次出现顺序(如 "abac" → "abc"),就不能用排序 —— 得换 std::unordered_set 记录已见字符,单次遍历构建新字符串。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
常见错误现象:
- 忘记
s.erase(),打印出来后面一堆乱码或旧字符残留 - 对
const std::string&尝试修改,编译失败 - 在循环里反复对同一字符串做 sort+unique,却没意识到每次都在重排,原始顺序彻底丢失
想保持首次出现顺序?手写遍历更可控
如果输入是 "programming",期望输出 "progamin"(去重但保序),std::sort+std::unique 完全失效。这时用哈希集合辅助即可:
std::string s = "programming";
std::unordered_set<char> seen;
std::string result;
for (char c : s) {
if (seen.insert(c).second) { // insert 返回 pair<iter bool>,second 为 true 表示新插入
result += c;
}
}
// result == "progamin"
</iter></char>
这个方案是 O(n) 时间,O(k) 空间(k 为不同字符数),且逻辑清晰、无副作用。真正需要“快速去重”的时候,得先问清楚:快是指 CPU 时间快,还是代码写得快?前者看数据规模和约束,后者往往手写几行比套模板更省事。
排序+unique 看似一行技巧,但隐含顺序破坏和大小写敏感两个硬限制,实际用之前最好先确认这两点是否可接受。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










