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
相关推荐
锅包一切1 小时前
PART7 队列
c++·学习·算法·leetcode·力扣·刷题·队列
Maỿbe1 小时前
动态规划之子数组问题
算法·动态规划
List<String> error_P2 小时前
经典回溯算法解析
python·算法
陆嵩2 小时前
从一个小例子学习方程组求解超节点(supernodal)算法
学习·算法·amd·重排·超节点·supernadal·消去树
Fms_Sa2 小时前
设计并实现日期类Date,它至少包含下列特性:
c++·算法
仰泳的熊猫2 小时前
题目1549:蓝桥杯算法提高VIP-盾神与积木游戏
数据结构·c++·算法·蓝桥杯
WW_千谷山4_sch2 小时前
MYOJ_11705:(洛谷P1137)旅行计划(经典拓扑排序)
c++·算法·动态规划·图论
FMRbpm2 小时前
string课后练习
c++·算法·新手入门