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--;
    }
}

逻辑完全一样,只是把下标换成了指针。你想想看,指针操作在嵌入式底层开发中更常见,因为很多时候你面对的是内存地址,而不是数组下标。

流程图:字符串反转的核心逻辑

下面这张图,把整个流程画清楚了。我建议你对照代码看一遍,印象会更深刻。

字符串原地反转流程图 开始 str == NULL ? (空指针检查) 返回 left = 0 right = len - 1 left < right ? 结束 交换 str[left] 和 str[right] left++ right--

性能对比

有人可能会问:用下标和用指针,性能有区别吗?

我实测过,在开启编译器优化的情况下,两者生成的汇编代码几乎一样。但在嵌入式裸机环境下,指针版本有时会少几条指令。不过说实话,这点差异在实际项目中完全可以忽略。你选自己顺手的写法就行。

实现方式 时间复杂度 空间复杂度 适用场景
双指针(下标) O(n) O(1) 通用,可读性好
双指针(指针) O(n) O(1) 嵌入式底层、内存操作
递归反转 O(n) O(n) 栈空间 不推荐,有栈溢出风险

小技巧:如果你在面试中遇到这道题,写完代码后主动问一句:「需要考虑 Unicode 或中文的情况吗?」——这会让面试官觉得你考虑问题很全面。

总结

字符串原地反转,说白了就是双指针交换。代码简单,但背后的细节不少:空指针检查、字符串存储位置、字符编码……每一个都可能是面试官挖的坑。

我在项目中用过这个函数不下几十次,从串口协议解析到 LCD 显示字符串,到处都有它的身影。嗯,基础的东西,往往最实用。


公众号:蓝海资料掘金营,微信 deep3321