分割回文串 | 刷题打卡

243 阅读2分钟

Leetcode 131. 分割回文串,难度:Medium
原题请戳这里

题目描述

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文串。返回 s 所有可能的分割方案。

回文串是正着读和反着读都一样的字符串。

示例1:

输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]

示例2:

输入:s = "a"
输出:[["a"]]

提示:

  • 1 <= s.length <= 16
  • s 仅由小写英文字母组成

思路分析

抓住本题关键字回文返回所有分割方案,就知道本题和DFS回溯少不了关系了。
题目可以理解为切分字符串s,切出的每一个子串必须是回文串,请找出所有切分的可能。由根节点s开始,枚举出可以切分掉的所有字符组合,如果切分掉的组合不是回文串,则不继续,如果是回文串,则基于切分后剩下的子串继续切分。这样可以画出一棵n叉树,从根节点到叶子节点的一条路径即为一种子集,回溯整棵树就可以得到所有的解。
另外,本题还涉及如何快速判断是否是回文串,可以和LeetCode 5. 最长回文子串结合起来看,使用动态规划,推导状态转移方程来辅助求解。

代码参考LeetCode@笨猪爆破组题解

AC代码

/**
 * @param {string} s
 * @return {string[][]}
 */
var partition = function(s) {
    const res = [];
    const dp = new Array(s.length);
    for (let i = 0; i < dp.length; i++) {
        dp[i] = new Array(s.length);
    }

    for (let j = 0; j < s.length; j++) {
        for (let i = 0; i <= j; i++) {
            if (i == j) {
                dp[i][j] = true;
            } else if (j - i == 1 && s[i] == s[j]) {
                dp[i][j] = true;
            } else if (j - i > 1 && s[i] == s[j] && dp[i + 1][j - 1]) {
                dp[i][j] = true;
            } else {
                dp[i][j] = false;
            }
        }
    }

    function dfs (temp, start) {
        if (start === s.length) {
            res.push(temp.slice());
            return;
        }
        for (let i = start; i < s.length; i++) {
            if (dp[start][i]) {
                temp.push(s.substring(start, i +1));
                dfs(temp, i + 1);
                temp.pop();
            }
        }
    }

    dfs([], 0);
    return res;
};

总结

本题相似题目:

用到的技巧

  • 定义 dp 子问题:dp[i][j]:从 ij 的子串是否回文。
    • dp[i][j]为真,罗列出所有的情况:
      1. i == j时,子串只有一个字符,肯定回文
      2. j-i == 1时,子串由两个字符组成,字符必须相同s[i] == s[j]
      3. j-i > 1时,子串由两个以上字符组成,s[i] == s[j],且dp[i+1][j-1]=true即除去首尾字符的剩余子串也是回文子串。

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情