给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: "aab"
输出:
[
["aa","b"],
["a","a","b"]
]
面对这种需要列出所有可能性的问题,很容易想到的就是使用回溯的方法来解决,分析问题,首先需要把一个复杂的问题分解成相对来说较为简单的子问题,然后将这个子问题的解进行组合就可以找到复杂问题的解了。
举例:
aabb
先考虑在第 1 个位置切割,a | abb
这样我们只需要知道 abb 的所有结果,然后在所有结果的头部把 a 加入
abb 的所有结果就是 [a b b] [a bb]
每个结果头部加入 a,就是 [a a b b] [a a bb]
aabb
再考虑在第 2 个位置切割,aa | bb
这样我们只需要知道 bb 的所有结果,然后在所有结果的头部把 aa 加入
bb 的所有结果就是 [b b] [bb]
每个结果头部加入 aa,就是 [aa b b] [aa bb]
aabb
再考虑在第 3 个位置切割,aab|b
因为 aab 不是回文串,所有直接跳过
aabb
再考虑在第 4 个位置切割,aabb |
因为 aabb 不是回文串,所有直接跳过
最后所有的结果就是所有的加起来
[a a b b] [a a bb] [aa b b] [aa bb]
对这个思路进行编码
class Solution {
String s;
List<List<String>> res = new ArrayList<>();
public List<List<String>> partition(String s) {
this.s = s;
List<String> list = new ArrayList<>();
dfs(list,0);
return res;
}
public void dfs(List<String> list,int index) {
//已经到了字符串的结尾了,把结果集放到最终解中
if (index == s.length()) {
res.add(new ArrayList<>(list));
return;
}
//不断取更长的头串
for (int i = index;i < s.length();i++) {
if (isPartition(index,i)) {//判断头串是否是回文
String temp = s.substring(index,i+1);
list.add(temp);
//对后面的字符串进行递归,进行相同的处理
dfs(list,i+1);
//删除结尾已有结果,回到上一层(回溯的精髓)
list.remove(list.size()-1);
}
}
}
//判断字符串的某一段是否是回文
public boolean isPartition(int start,int end) {
while (start < end) {
if (s.charAt(start) != s.charAt(end)) {
return false;
}
start++;
end--;
}
return true;
}
}
其实这样是比较直接的解决问题了,这个解法中还有可以优化的地方,就是判断是否是回文的地方,我们会有很多重复的判断。比如已经判断过“aa”是回文了,但是判断“baab”是否是回文的时候还会重复判断,这个地方是可以优化的,我们可以用一个二维空间记录判断过回文的字符串,这样就不用重复的进行判断了。