字符串反转大作战:从“hello”到“olleh”,我悟了!

8 阅读4分钟

今天不聊人生理想,也不谈前端框架内卷,咱们来一场字符串的花式反转派对
你以为反转只是 reverse()?No no no~在力扣(LeetCode)的世界里,反转是一门艺术,更是一场修行

本文带你一口气刷透四道经典字符串反转题,从入门到进阶,从“翻转单词”到“检测重复子串”,边笑边学,笑着通过面试


🔥 题目一:151. 反转字符串中的单词 —— “倒着说话”的艺术

🎯 题意简述:

输入:" hello world "
输出:"world hello"
要求:去掉多余空格,只保留单词间一个空格,顺序完全颠倒

💡 思考过程:

很多人第一反应是:split(' ') → filter → reverse → join(' ')
确实能过,但——面试官微微一笑:“还有更优雅的原地处理方式吗?”

于是我们祭出双指针 + 倒序遍历大法:

var reverseWords = function(s) {
    let str = '', res = '';
    for (let i = s.length - 1; i >= 0; i--) {
        // 拼单词(注意:字符加在前面!)
        while (i >= 0 && s[i] !== ' ') {
            str = s[i] + str;
            i--;
        }
        if (str) {
            res += str + ' ';
            str = '';
            i++; // 关键回退!
        }
    }
    return res.slice(0, -1); // 删掉最后那个多余的空格
};

🤔 为什么 i++

因为内层 while 结束时,i 已经指向空格或 -1。外层 for 还会再 i--,所以必须 i++ 抵消一次,不然会漏字符!这步堪称“灵魂回退”。

小贴士:这种写法不用额外数组,空间 O(1)(忽略结果字符串),时间 O(n),完美!


🔁 题目二:344. 反转字符串 —— 最朴素的浪漫

🎯 题意简述:

["h","e","l","l","o"] 变成 ["o","l","l","e","h"]原地修改,不准开新数组

💡 解法:左右指针对撞

var reverseString = function(s) {
    for (let i = 0, j = s.length - 1; i < j; i++, j--) {
        [s[i], s[j]] = [s[j], s[i]]; // ES6 解构交换,优雅永不过时
    }
};

⚠️ 注意循环条件是 i < j,不是 i < s.length / 2 虽然效果一样,但前者更直观!

这题看似简单,却是所有反转操作的基石。记住:对撞指针,yyds!


🔍 题目三:459. 重复的子字符串 —— 字符串的“套娃”检测术

🎯 题意简述:

判断 "abab" 是否由 "ab" 重复构成?
答案:✅ 是!

💡 神仙解法(来自官方脑洞):

把字符串复制一份拼接:ss = s + s
然后去掉首尾字符:newStr = ss.slice(1, -1)
如果 newStr 中还能找到原字符串 s,那它就是重复子串构成的!

var repeatedSubstringPattern = function(s) {
    const ss = s + s;
    return ss.slice(1, -1).includes(s);
};

🤯 原理揭秘:

假设 s = "abcabc",那么 ss = "abcabcabcabc"
去掉首尾 → "bcabcabcab"
中间依然包含 "abcabc"
因为重复结构在拼接后会产生“冗余匹配窗口”

这招叫 KMP 的民间智慧版,虽然没显式用 KMP,但思想异曲同工。面试说出来,面试官眼睛会发光✨!


🧩 题目四:541. 反转字符串 II —— 分段反转,节奏大师

🎯 题意简述:

2k 个字符为一组,只反转前 k
比如 "abcdefg", k=2"bacdfeg"

💡 解法:分块处理 + 局部反转

var reverseStr = function(s, k) {
    let arr = s.split("");
    for (let i = 0; i < arr.length; i += 2 * k) {
        let start = i;
        let end = Math.min(i + k - 1, arr.length - 1);
        while (start < end) {
            [arr[start], arr[end]] = [arr[end], arr[start]];
            start++;
            end--;
        }
    }
    return arr.join("");
};

🎵 节奏感拉满:

  • i += 2k:每次跳过一个完整周期
  • end = min(i + k - 1, n-1):防止越界
  • 内部用对撞指针反转前 k

这题考验你对边界控制分段逻辑的理解。写对了,说明你已经掌握了“局部操作全局”的思维!


🎉 总结:反转的哲学

题号核心思想技巧关键词
151倒序遍历 + 手动拼词回退指针、空格处理
344对撞指针原地交换
459字符串自拼接数学构造、包含检测
541分块 + 局部反转步长控制、边界防御

反转不是目的,理解结构才是
这些题背后,藏着字符串处理的通用范式:双指针、分治、边界处理、空间优化


💬 最后说两句

刷题不是为了背答案,而是为了培养“看到问题就想到模式”的直觉
下次遇到字符串,别慌——先问自己:

“我能用双指针吗?需要分段吗?要不要去空格?能不能构造新串?”

答案,往往就在问题之中