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();
}
}