LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白

不知道你有没有这种感觉。 刚学回溯算法的时候,组合、子集这类数组题,照着模板套还能写个七七八八。 一碰到字符串切割,直接懵圈。

我第一次刷这道题的时候,盯着屏幕盯了半小时,连 "第一刀该落在哪" 都没想明白。

题目说啥

其实题意特别简单。 给你一个字符串,让你把它切成若干段子串,要求每一段都必须是回文串。 最后返回所有合法的切割方案。

比如输入 "aab",既可以切成 ["a","a","b"],也可以切成 ["aa","b"],这两种都是正确答案。

我是怎么想到回溯的

但凡题目说 "找出所有可能的方案",第一反应就可以往回溯上靠。 本质就是暴力枚举所有情况,不行就回头重来。

但切割问题最绕的地方,就是怎么表示 "当前切到哪了"。 我一开始傻乎乎地想,难道要存所有切割点的位置? 后来才突然开窍:这和组合题的 startIndex 根本就是一个道理啊。

我们用一个 start 变量表示当前这段子串的起始位置 ,然后从 start 开始往后遍历。 每走到一个位置 i,就相当于在这里切一刀,看看 s[start..i] 是不是回文。 如果是回文,就把这段放进当前路径,然后递归处理 i+1 开头的剩下的字符串。 等递归回来,再把这段拿出来,继续往后试下一个切割点。

说白了,就是每次先确定一段回文前缀,剩下的部分交给递归去解决。 等到 start 走到字符串末尾的时候,说明一整段都切完了,这就是一组合法方案。

判断回文就很直接了,双指针两头往中间夹,挨个比对字符就行。 这个地方我一开始还踩过坑,左右边界搞错了,连着错了好几个用例。

javascript 复制代码
var partition = function(s) {
    const res = [];
    const path = [];
    const n = s.length;

    // 判断 s[left..right] 是不是回文串
    const isPalindrome = (left, right) => {
        while (left < right) {
            if (s[left] !== s[right]) return false;
            left++;
            right--;
        }
        return true;
    };

    const backtrack = (start) => {
        // 切到末尾了,说明找到一组合法解,存起来
        if (start === n) {
            res.push([...path]);
            return;
        }

        // 从当前起点开始,挨个试切到 i 的位置行不行
        for (let i = start; i < n; i++) {
            // 不是回文?这刀切不了,跳过
            if (!isPalindrome(start, i)) continue;
            
            // 能切,把这段子串加入当前路径
            path.push(s.slice(start, i + 1));
            // 递归切剩下的后半段
            backtrack(i + 1);
            // 回溯,撤销这一刀,试试下一个位置
            path.pop();
        }
    };

    backtrack(0);
    return res;
};

你看,整个结构和组合题几乎一模一样。 我当时最容易写错的就是终止条件,好几次写成 i === n 才收集结果,怎么调都不对。 记住:是 start 走到头的时候,才说明一整段都切完了。

复杂度唠两句

时间复杂度大概是 O (n * 2^n),最坏情况每个位置都能切,一共 2^(n-1) 种分割方式,每次判断回文要 O (n)。 空间是 O (n),主要是递归栈和路径数组的开销。

最后说两句

这道题我前前后后刷了三遍才彻底吃透。 说穿了就是回溯模板的字符串切割版,核心就是用 startIndex 控制切割的起点。

给你们提几个我踩过的坑:

  • 别把终止条件写错,是 start 等于字符串长度时收集结果,不是 i
  • 注意字符串索引和 slice 的左闭右开特性,别搞混边界。
  • 判断回文的双指针别写反左右边界,不然很容易出现越界或者判断错误。

掌握了这道题,基本上所有字符串切割类的回溯题,你都能快速找到思路。

你刚学回溯的时候,是不是也在切割问题上卡过壳? 或者你有更巧妙的写法? 评论区聊聊呗,我每条都会看~ 如果觉得有帮助,点个赞让更多小伙伴看到呀。

相关推荐
江畔柳前堤8 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore9 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考10 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX11 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
avi911112 小时前
[AI教做人]AI平台做2项目;一个3D模型展示,另一个框架多人
javascript·人工智能·ai·3d模型·3d引擎·顶点和法线
爱跳舞的烤冷面12 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
kyriewen12 小时前
我用Claude Code两天干完了团队两周的排期——周报发出去那一刻我就后悔了
前端·javascript·ai编程
猎嘤一号12 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽12 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI12 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研