题目: 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。返回 s 所有可能的分割方案。
输入: "aab"
输出: [ ["aa","b"] ["a","a","b"] ]
回溯 DFS递归树:
1、每一个结点表示剩余没有扫描到的字符串
2、产生前缀字符串的时候,判断前缀字符串是否是回文。
如果前缀字符串是回文,则可以产生分支和结点;
如果前缀字符串不是回文,则不产生分支和结点,这一步是剪枝操作。
3、在叶子结点是空字符串的时候结算(临时路径加入ans中),此时从根结点到叶子结点的路径,就是结果集里的一个结果,使用深度优先遍历,记录下所有可能的结果。
所以在调用DFS之前,已经知道哪些子串是回文了,递归只是为了取出来这些串。
public List<List<String>> partition(String s) {
List<List<String>> ans = new ArrayList<>();
int len = s.length();
if (len == 0) return ans;
// dp是表示i,j之间字符串是否回文,这里回文判断方法见hot.647题解
boolean[][] dp = new boolean[len][len];
for (int i = len - 1; i >= 0; --i) {
for (int j = i; j < len; ++j) {
if (s.charAt(i) == s.charAt(j)) {
if (j - i < 3 || dp[i + 1][j - 1])
dp[i][j] = true;
}
}
}
helper(ans, new LinkedList<String>(), dp, s, 0);
return ans;
}
void helper(List<List<String>> ans, LinkedList<String> path, boolean[][] dp,
String s, int start) {
if (start == s.length()) {// 结算本条dfs路径
ans.add(new LinkedList<>(path));
return;
}
for (int i = start; i < s.length(); ++i) {
if (dp[start][i]) {
path.addLast(s.substring(start, i + 1));// 字符串加入path
helper(ans, path, dp, s, i + 1);
path.removeLast();// 回溯
}
}
}