c++oding="utf-8" ?>
std::unique 配合 erase 是删除字符串中所有连续重复字符的首选方法,它原地修改、保留每组首字符、时间复杂度 o(n);但 unique 仅移除相邻重复项且不缩容,必须用 erase 截断尾部冗余,写法为 s.erase(std::unique(s.begin(), s.end()), s.end())。

用 std::unique 配合 erase 是最常用且高效的做法
直接修改原字符串、保留第一个出现的字符、时间复杂度 O(n),这是生产环境首选。但要注意:std::unique 不真正删除元素,只是把重复项移到末尾,必须搭配 erase 才能缩容。
-
std::unique要求容器支持随机访问迭代器,std::string满足条件 - 它只移除「相邻重复」,不处理全局去重(比如
"abac"中的两个'a'不相邻,不会被删) - 写法是
s.erase(std::unique(s.begin(), s.end()), s.end()),漏掉erase就白干 - 如果字符串很大,这个操作是 in-place 的,比新建字符串省空间
手写双指针循环适合需要自定义逻辑的场景
比如你想跳过某些字符(如空格或标点)、或只对字母做去重、或保留最多 k 个连续相同字符,这时候 std::unique 不够用,得自己遍历。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 用两个下标
i(写入位置)和j(读取位置),初始都为 0 - 只要
j没到末尾,就比较s[j]和s[j-1](注意 j==0 时跳过判断) - 不相等时才把
s[j]写到s[i++],最后用s.resize(i)截断 - 边界容易错:j 从 1 开始,i 从 0 开始,别越界;空字符串要提前返回
正则替换在简单脚本中可行,但 C++ 标准库正则性能差且易出错
像 std::regex_replace(s, std::regex("(.)\1+"), "$1") 看似简洁,实际问题很多。
- C++11 的
std::regex在多数编译器(尤其 libstdc++)里实现不完善,匹配失败或崩溃很常见 - 构造正则对象开销大,反复调用时别在循环里 new regex
- 捕获组编号、转义规则(比如
"\1"还是"$1")依赖具体标准库,移植性差 - 仅建议用于一次性小文本处理,或已确认目标平台 regex 稳定
注意 Unicode 字符串不能直接用上述方法
所有上面的方法都按字节/码元操作,对 UTF-8 编码的中文、emoji 会出错——比如一个汉字占 3 字节,std::unique 可能把中间字节当重复删掉。
- 真要处理 Unicode,先用
std::wstring+ UTF-32,或借助 ICU、utf8cpp 等库转成 code point 序列再处理 - 不要试图用
substr(0, 1)截 UTF-8 字符,很可能截断多字节序列 - 日常英文 ASCII 场景没问题,但一旦输入可能含非 ASCII,就得立刻切换方案
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










