LeetCode第131题

难度:中等

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

示例1:

输入:s = "aab"

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

示例2:

输入:s = "a"

输出\["a"]

  • 1 <= s.length <= 16

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

问题分析

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

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

判断子串是否是回文串,我们可以预处理,先计算好哪些子串是回文串哪些不是。如果子串si,j是回文串,需要两边的字符相等si==sj,并且中间的子串si+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
相关推荐
血色橄榄枝5 小时前
基于用户注册信息的关键词检测挑战赛「Datawhale AI 夏令营」
人工智能·算法·机器学习
c238566 小时前
第二篇:《测试指挥官:可视化单题自测框架(含 assert 实操)》
java·数据库·c++·算法·安全性测试
六点_dn7 小时前
Linux学习笔记-printf命令
linux·运维·算法
遥感知识服务7 小时前
Sentinel-1 + DEM + FwDET + 随机森林:从快速水深初估到多因子误差修正
算法·随机森林·sentinel
来一碗刘肉面8 小时前
顺序表与链表的比较
数据结构·算法·链表
alphaTao8 小时前
LeetCode 每日一题 2026/7/13-2026/7/19
算法·leetcode
nnerddboy8 小时前
脑电信号处理实战 03 | 运动想象脑机接口入门:ERD/ERS、CSP 空间滤波与左右拳想象解码
算法·信号处理
QN1幻化引擎9 小时前
Dalin L — 我造了一门支持中文编程的语言,完整移植到 Rust 了
人工智能·算法·机器学习
Rainy Blue8839 小时前
C转C++速成
c语言·c++·算法
txzrxz9 小时前
二分图详解
数据结构·c++·算法·图论·深度优先搜索·二分图染色