Loading

Medium | LeetCode 131. 分割回文串 | 回溯 + 动态规划预处理

131. 分割回文串

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

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

示例 1:

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

示例 2:

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

提示:

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

解体思路

方法一:回溯 + 动态规划预处理

先使用动态规划计算出字符串S中[i, j]是否为回文串。然后采用回溯的方法, 找到所有的子集。把不是回文串的子集过滤掉。

public List<List<String>> partition(String s) {
    int len = s.length();
    List<List<String>> res = new ArrayList<>();
    if (len == 0) {
        return res;
    }

    // 预处理
    // 状态:dp[i][j] 表示 s[i][j] 是否是回文
    boolean[][] dp = new boolean[len][len];
    // 状态转移方程:在 s[i] == s[j] 的时候,dp[i][j] 参考 dp[i + 1][j - 1]
    for (int right = 0; right < len; right++) {
        // 注意:left <= right 取等号表示 1 个字符的时候也需要判断
        for (int left = 0; left <= right; left++) {
            if (s.charAt(left) == s.charAt(right) && (right - left <= 2 || dp[left + 1][right - 1])) {
                dp[left][right] = true;
            }
        }
    }

    Deque<String> stack = new ArrayDeque<>();
    backtracking(s, 0, len, dp, stack, res);
    return res;
}

private void backtracking(String s,
                          int start,
                          int len,
                          boolean[][] dp,
                          Deque<String> path,
                          List<List<String>> res) {
    if (start == len) {
        res.add(new ArrayList<>(path));
        return;
    }

    for (int i = start; i < len; i++) {
        // 剪枝[start, i] 这部分不是回文串
        if (!dp[start][i]) {
            continue;
        }
        path.addLast(s.substring(start, i + 1));
        backtracking(s, i + 1, len, dp, path, res);
        path.removeLast();
    }
}
posted @ 2021-05-15 14:58  反身而诚、  阅读(44)  评论(0编辑  收藏  举报