已通过编译运行验证,输出均符合预期。下面是完整讲解。
核心思路(原地算法)
三步法,时间复杂度 O(n),额外空间 O(1)(不计返回所需):
- 清理空格:去掉前导、尾随空格,把中间多个连续空格压缩成单个空格
- 整体反转整个字符串
- 逐个反转每个单词
为什么这样做能对?
例:
““the sky is blue””
- 清理后:
““the sky is blue””(本例无需改动) - 整体反转:
““eulb si yks eht”” - 逐词反转:
““blue is sky the”” ✅
C 语言实现
// LeetCode 151. 反转字符串中的单词
#include <string.h>
/* 反转 s[left…right] */
void reverse(char *s, int left, int right) {
while (left < right) {
char tmp = s[left];
s[left] = s[right];
s[right] = tmp;
left++;
right–;
}
}
char *reverseWords(char *s) {
int len = strlen(s);
int i = 0, j = 0;
// 第一步:清理空格(双指针原地压缩) while (i < len && s[i] == ' ') i++; // 跳过前导空格 while (i < len) { if (s[i] != ' ') { s[j++] = s[i++]; // 非空格字符直接拷贝 } else { // 空格:仅当结果末尾不是空格时才写入一个 if (j > 0 && s[j - 1] != ' ') { s[j++] = ' '; } i++; } } if (j > 0 && s[j - 1] == ' ') j--; // 去掉末尾可能残留的空格 s[j] = '\0'; int newLen = j; // 第二步:整体反转 reverse(s, 0, newLen - 1); // 第三步:逐个反转每个单词 int start = 0; for (int k = 0; k <= newLen; k++) { if (s[k] == ' ' || s[k] == '\0') { reverse(s, start, k - 1); start = k + 1; } } return s;}
关键点解析
- 空格清理的双指针技巧
“i” 读、
“j” 写,
“j” 始终指向"已处理好的有效部分"的下一个位置。判断
“s[j-1] != ’ '” 是为了防止连续空格被写成多个。
- 必须处理三种多余空格
位置 例子 处理方式
前导
“” hello"" 循环开始前
“while (s[i]’ ‘) i++"
中间连续
““a b””
"if (s[j-1]!=’ ')" 才写入
尾随
""hi “” 写完后
"if (s[j-1]’ ') j–”
- 边界条件
- 空字符串
“”“” → 返回
“”“” - 全空格
“” “” → 清理后
“j==0”,直接返回空串 - 单单词
““hello”” → 整体反转后再反转回来,结果不变
- C 语言特有注意
- 参数
“char *s” 在 LeetCode 中指向可写内存,可直接修改 - 本地测试必须用字符数组
“char s[] = “…”;”,不能用
“char *s = “…”;”(字符串常量,修改会段错误)
复杂度
- 时间:O(n),字符串遍历常数次
- 空间:O(1),原地修改,无额外数组
完整代码与测试用例已保存,可直接编译运行验证: