56、字符串反转:如何原地反转一个字符串?
字符串反转,这道题在面试里出现的频率,说实话,高得有点离谱。我当年刚入行时,第一次面试就被问到了。当时我心想:这还不简单?直接开个新数组倒着拷贝不就完了?
面试官笑了笑,补了一句:「原地反转,空间复杂度 O(1)。」
嗯,这才是这道题真正的考点。
什么是「原地」反转?
所谓原地,就是不能额外申请一块和原字符串等长的内存。你只能在原数组上动手脚,通过交换字符来完成反转。
说白了,就是两个指针,一个从头,一个从尾,往中间走,边走边交换。
核心思想:双指针 + 对称交换。时间复杂度 O(n),空间复杂度 O(1)。
代码实现
我习惯用 C 语言来实现,因为 C 里字符串就是字符数组,操作起来最直观。下面这个版本,我建议你背下来——不是死记硬背,而是理解它的每一行。
#include <stdio.h>
#include <string.h>
void reverse_string(char *str) {
if (str == NULL) return; // 空指针检查,我吃过亏
int left = 0;
int right = strlen(str) - 1;
char temp;
while (left < right) {
// 交换左右字符
temp = str[left];
str[left] = str[right];
str[right] = temp;
left++;
right--;
}
}
int main() {
char s[] = "Hello, World!";
printf("原字符串: %s\n", s);
reverse_string(s);
printf("反转后: %s\n", s);
return 0;
}
你看,代码就这么几行。但越是简单的代码,越容易出问题。
避坑指南
我曾经在项目里用过一个类似的函数,结果程序跑着跑着就崩了。查了半天,发现是传进来的字符串是 const char *,直接写入了只读区。
这里有几个坑,我帮你列出来:
- 字符串字面量不能修改:
char *p = "hello";这种写法,p 指向的是只读区,不能反转。必须用字符数组char p[] = "hello";。 - 空字符串和单字符:while 循环条件
left < right天然处理了这两种情况,不需要额外判断。 - 中文字符串:C 语言里一个中文字符占多个字节,直接交换会乱码。如果你做嵌入式开发,遇到 UTF-8 编码的字符串,要按字符边界处理,不能简单按字节交换。
警告:不要用 strlen() 的结果作为循环条件反复调用。每次调用 strlen 都是 O(n) 的遍历,放在 while 里会让整体复杂度变成 O(n²)。正确的做法是:先算一次,存到变量里。
另一种写法:用指针
我个人更喜欢用指针来写,感觉更「C 语言」一些。你看这个版本:
void reverse_string_ptr(char *str) {
if (str == NULL) return;
char *left = str;
char *right = str + strlen(str) - 1;
while (left < right) {
char temp = *left;
*left = *right;
*right = temp;
left++;
right--;
}
}
逻辑完全一样,只是把下标换成了指针。你想想看,指针操作在嵌入式底层开发中更常见,因为很多时候你面对的是内存地址,而不是数组下标。
流程图:字符串反转的核心逻辑
下面这张图,把整个流程画清楚了。我建议你对照代码看一遍,印象会更深刻。
性能对比
有人可能会问:用下标和用指针,性能有区别吗?
我实测过,在开启编译器优化的情况下,两者生成的汇编代码几乎一样。但在嵌入式裸机环境下,指针版本有时会少几条指令。不过说实话,这点差异在实际项目中完全可以忽略。你选自己顺手的写法就行。
| 实现方式 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 双指针(下标) | O(n) | O(1) | 通用,可读性好 |
| 双指针(指针) | O(n) | O(1) | 嵌入式底层、内存操作 |
| 递归反转 | O(n) | O(n) 栈空间 | 不推荐,有栈溢出风险 |
小技巧:如果你在面试中遇到这道题,写完代码后主动问一句:「需要考虑 Unicode 或中文的情况吗?」——这会让面试官觉得你考虑问题很全面。
总结
字符串原地反转,说白了就是双指针交换。代码简单,但背后的细节不少:空指针检查、字符串存储位置、字符编码……每一个都可能是面试官挖的坑。
我在项目中用过这个函数不下几十次,从串口协议解析到 LCD 显示字符串,到处都有它的身影。嗯,基础的东西,往往最实用。
公众号:蓝海资料掘金营,微信 deep3321