LeetCode第131题

难度:中等

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

示例1:

输入:s = "aab"

输出:[["a","a","b"],["aa","b"]]

示例2:

输入:s = "a"

输出:[["a"]]

  • 1 <= s.length <= 16

  • s 仅由小写英文字母组成

问题分析

这题让把字符串分割成一些子串,并且要保证每个子串都是回文串,这是一道经典的回溯算法问题,关于回溯算法,可以看下很早之前写的一篇文章《什么叫回溯算法,一看就会,一写就废》。

对原字符串不断的截取子串,如果子串是回文串就继续截取,如果不是回文串就跳过,最后如果都截取完了,说明截取的子串都是回文串,把截取的子串保存下来即可。可以看到子串的截取就像一个 n 叉树一样,如下图所示。

判断子串是否是回文串,我们可以预处理,先计算好哪些子串是回文串哪些不是。如果子串s[i,j]是回文串,需要两边的字符相等s[i]==s[j],并且中间的子串s[i+1,j-1]也必须是回文串。

JAVA:

复制代码
public List<List<String>> partition(String s) {
    List<List<String>> ans = new ArrayList<>();
    int length = s.length();
    // 预处理,先计算子串中哪些是回文的,哪些不是,
    // 数组dp[i][j]表示子串s[i,j]是否是回文的。
    boolean[][] dp = new boolean[length][length];
    for (int j = 0; j < length; j++) {
        for (int i = 0; i <= j; i++) {
            // 如果子串s[j,i]是回文串,则两边的字符s[i]和s[j]必须相同,并且
            // 中间的子串s[i+1,j-1]如果存在,也必须是回文串。
            if (s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[i + 1][j - 1]))
                dp[i][j] = true;
        }
    }

    backTrack(s, dp, 0, ans, new ArrayList<>());// 回溯算法
    return ans;
}

private void backTrack(String s, boolean[][] dp, int index, List<List<String>> ans, List<String> path) {
    // 边界条件判断,字符串s中的字符都访问完了
    if (index >= s.length()) {
        ans.add(new ArrayList<>(path));
        return;
    }
    for (int i = index; i < s.length(); i++) {
        // 如果当前截取的子串不是回文的,就跳过
        if (!dp[index][i]) continue;
        // 这里截取的子串s[index][i]就是回文串。
        path.add(s.substring(index, i + 1));// 做出选择
        backTrack(s, dp, i + 1, ans, path); // 递归
        path.remove(path.size() - 1);// 撤销选择
    }
}

C++:

复制代码
public:
    vector<vector<string>> partition(string s) {
        vector<vector<string>> ans;
        int length = s.length();
        // 预处理,先计算子串中哪些是回文的,哪些不是,
        // 数组dp[i][j]表示子串s[i,j]是否是回文的。
        vector<vector<bool>> dp(length, vector<bool>(length, false));
        for (int j = 0; j < length; j++) {
            for (int i = 0; i <= j; i++) {
                // 如果子串s[j,i]是回文串,则两边的字符s[i]和s[j]必须相同,并且
                // 中间的子串s[i+1,j-1]如果存在,也必须是回文串。
                if (s[i] == s[j] && (j - i <= 2 || dp[i + 1][j - 1]))
                    dp[i][j] = true;
            }
        }
        vector<string> path{};
        backTrack(s, dp, 0, ans, path);// 回溯算法
        return ans;
    }

    void backTrack(string &s, vector<vector<bool>> &dp, int index,
                   vector<vector<string>> &ans, vector<string> &path) {
        // 边界条件判断,字符串s中的字符都访问完了
        if (index >= s.length()) {
            ans.push_back(path);
            return;
        }
        for (int i = index; i < s.length(); i++) {
            // 如果当前截取的子串不是回文的,就跳过
            if (!dp[index][i])
                continue;
            // 这里截取的子串s[index][i]就是回文串。
            path.push_back(s.substr(index, i - index + 1));// 做出选择
            backTrack(s, dp, i + 1, ans, path); // 递归
            path.pop_back();// 撤销选择
        }
    }

Python:

复制代码
def partition(self, s: str) -> List[List[str]]:
    def backTrack(index):
        # 边界条件判断,字符串s中的字符都访问完了
        if index >= length:
            ans.append(path[:])
            return
        for i in range(index, length):
            # 如果当前截取的子串不是回文的,就跳过
            if not dp[index][i]:
                continue
            # 这里截取的子串s[index][i]就是回文串。
            path.append(s[index: i + 1])  # 做出选择
            backTrack(i + 1)  # 递归
            path.pop()  # 撤销选择

    ans = []
    path = []
    length = len(s)
    # 预处理,先计算子串中哪些是回文的,哪些不是,
    # 数组dp[i][j]表示子串s[i,j]是否是回文的。
    dp = [[False] * length for _ in range(length)]
    for j in range(length):
        for i in range(j + 1):
            # 如果子串s[i,j]是回文串,则两边的字符s[i]和s[j]必须相同,并且
            # 中间的子串s[i+1,j-1]如果存在,也必须是回文串。
            if s[i] == s[j] and (j - i <= 2 or dp[i + 1][j - 1]):
                dp[i][j] = True
    backTrack(0)  # 回溯算法
    return ans
相关推荐
今儿敲了吗几秒前
41| 快速乘
数据结构·c++·笔记·学习·算法
ysa0510304 分钟前
树的定向(dfs并查集贪心)
数据结构·c++·笔记·算法·深度优先·图论
mjhcsp28 分钟前
C++ A* 算法:启发式路径搜索的黄金标准
android·c++·算法
仰泳的熊猫44 分钟前
题目2281:蓝桥杯2018年第九届真题-次数差
数据结构·c++·算法·蓝桥杯
blackicexs1 小时前
第九周第一天
数据结构·算法
小小怪7501 小时前
C++中的代理模式高级应用
开发语言·c++·算法
Dfreedom.1 小时前
归一化技术全景指南
深度学习·算法·机器学习·归一化
Genevieve_xiao1 小时前
【写给新人】在 vscode 中配置适用于算法竞赛背景的 c/c++
c语言·vscode·算法
TracyCoder1231 小时前
LeetCode Hot100(70/100)—— 322. 零钱兑换
算法·leetcode·职场和发展
2401_891482171 小时前
C++中的观察者模式
开发语言·c++·算法