双指针原地去重空格最省空间,核心是write指针写入有效字符、read指针扫描;遇非空格直接复制,遇空格仅当前一字符非空格时才写入,末尾需补'\0'。

用双指针原地去重空格最省空间
连续空格合并本质是数组去重变种,核心思路是用一个写指针 write 记录有效字符位置,读指针 read 扫描整个数组。遇到非空格直接复制;遇到空格时,只在前一个字符不是空格时才写入——这样就跳过了连续空格中的冗余部分。
注意:必须保证数组末尾有足够空间容纳结果(比如原长度为 n,结果最多 n 字符,但若开头/结尾有空格,实际会更短);还要手动补 '\0' 终止符。
char s[] = "a b c";
int n = strlen(s);
int write = 0;
for (int read = 0; read < n; read++) {
if (s[read] != ' ') {
s[write++] = s[read];
} else if (write == 0 || s[write-1] != ' ') {
s[write++] = ' ';
}
}
s[write] = '\0'; // 关键!否则后续输出可能越界
用 std::string + std::stringstream 最简洁但不保空格位置
如果原始数据是 std::string,且你只需要“单词间单空格”,不关心首尾空格或原格式,std::stringstream 是最短路径:它默认按空白符切分并忽略连续空白。
- 优点:代码三行,无边界风险,自动处理首尾空格
- 缺点:无法保留开头/结尾空格,也不能区分 tab 和 space
- 若需保留首尾空格,得改用
std::istringstream配合getline按空格手动拆
std::string s = " hello world ";
std::stringstream ss(s);
std::string word, result;
while (ss >> word) {
if (!result.empty()) result += " ";
result += word;
}
// result == "hello world"
用正则 std::regex_replace 最灵活但性能差
当需要精确控制“哪些空白要合并”(比如只合并空格、不碰制表符),或要同时处理多种空白组合时,正则最直接。C++11 起支持 std::regex,模式 " +" 表示一个及以上空格。
立即学习“C++免费学习笔记(深入)”;
- 注意:MSVC 在较老版本中 regex 实现有 bug,GCC/Clang 更稳
- 编译需加
-std=c++11及以上,且正则构造开销大,别在高频循环里用 - 若输入含大量空格,
regex_replace内部多次内存分配,比双指针慢一个数量级
std::string s = "a \t b c"; // 含 tab,正则默认不匹配
std::string result = std::regex_replace(s, std::regex(" +"), " ");
// result == "a \t b c" —— tab 没被碰,符合预期
合并后仍要保留首尾空格?得单独处理
几乎所有方案(包括双指针和 stringstream)默认丢弃首尾空格。如果你的业务逻辑要求“中间空格压缩,首尾照旧”,就不能依赖通用方法,得先记录首尾空格数,再对中间部分操作。
- 用
s.find_first_not_of(' ')和s.find_last_not_of(' ')定位有效区间 - 对子串调双指针或 regex,再拼回首尾空格
- 特别注意:若整个字符串全是空格,这两个函数返回
std::string::npos,必须判空
这一步容易漏,尤其测试用例只覆盖了“中间有内容”的场景。


















