关于回溯算法的一般解题步骤,和回溯算法的应用,博主在上个文章可以讲过,建议大家没有看过上一篇文章的可以先去看一下。
问题
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: “aab”
输出: [ [“aa”,“b”], [“a”,“a”,“b”] ]
思路
本题这涉及到两个关键问题:
切割问题,有不同的切割方式
判断回文
相信这里不同的切割方式可以搞懵很多同学了。
这种题目,想用for循环暴力解法,可能都不那么容易写出来,所以要换一种暴力的方式,就是回溯。
一些同学可能想不清楚 回溯究竟是如何切割字符串呢?
我们来分析一下切割,其实切割问题类似组合问题。
例如对于字符串abcdef:
组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个.....。
切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段.....。
感受出来了不?
所以切割问题,也可以抽象为一棵树形结构,如图:
代码
class Solution_131 {
List<List<String>> result = new ArrayList<>();
public List<List<String>> partition(String s) {
List<String> temp = new ArrayList<>();
backtracking(temp,0,s);
return result;
}
private void backtracking(List<String> temp , int startIndex , String s){
if (startIndex >= s.length()){
// 判断回文串的逻辑在确定单层逻辑的地方写了,也可以在收集结果的时候判断一下
result.add(new ArrayList<>(temp));
}
for (int i = startIndex; i < s.length(); i++) {
if (isPalindrome(s,startIndex,i)){
temp.add(s.substring(startIndex,i+1));
}else {
continue;
}
backtracking(temp,i+1,s);
temp.remove(temp.size()-1);
}
}
public boolean isPalindrome(String s , int startIndex , int end ){
for (int i = startIndex , j = end; i < j ; i++ , j--) {
if (s.charAt(i) != s.charAt(j)){
return false;
}
}
return true;
}
}
总结
- 好的代码都是修改出来的。代码优化部分,第一点:就是在判断回文串的过程可以进行优化,可以选择更高效的判断方式,或者使用动态规划提前将所有结果判断出来,在需要使用的过程中直接进行查询使用即可
- 切割问题可以抽象为组合问题
- 如何模拟那些切割线
- 切割问题中递归如何终止
- 在递归循环中如何截取子串
- 如何判断回文
- 关于模拟切割线,其实就是index是上一层已经确定了的分割线,i是这一层试图寻找的新分割线