分享完回溯解决组合问题、子集问题与全排列问题,这次分享利用回溯来解决分割问题。下面先给出回溯的模板代码。
private void backtracking(参数1,参数2,...){
if(递归终止条件){
收集结果;
return;
}
for(遍历集合){
处理;
backtracking(参数1,参数2,...); // 递归;
回溯;
}
}
分割回文串
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是
回文串。返回 s 所有可能的分割方案。
示例 1:
输入:s = “aab”
输出:[[“a”,“a”,“b”],[“aa”,“b”]]
class Solution {
List<List<String>> ans = new ArrayList<>();
List<String> path = new ArrayList<>();
public List<List<String>> partition(String s) {
backtracking(s, 0);
return ans;
}
private void backtracking(String s, int startIndex){
if(startIndex == s.length()){
ans.add(new ArrayList<>(path));
return;
}
for(int i = startIndex;i < s.length();i++){
if(!isValid(s.substring(startIndex, i + 1))) continue;
path.add(s.substring(startIndex, i + 1));
backtracking(s, i + 1);
path.remove(path.size() - 1);
}
}
private boolean isValid(String str){
int l = 0;
int r = str.length() - 1;
while(l < r){
if(str.charAt(l++) != str.charAt(r--)){
return false;
}
}
return true;
}
}
首先定义了一个ans集合用于回收所有符合条件的分割子串,定义path用于收集遍历过程中分割出来的子串,如果path中子串都为回文串,则将其加入到ans中。在partition方法中调用了backtracking方法收集所有符合条件的分割子串,最终返回ans集合。isValid方法用于判断某个子串是否为回文串(如果不明白,可以看看回文串首篇)。
利用上述示例,说明backtracking代码的执行流程。进入backtracking,startIndex等于0,不等于需要分割字符串长度,进入for循环,截取字符串aab的首个字母a,一个字母也是回文串,isValid返回true,将字母a加入到path中,path为[a],接着递归进入下一个backtracking,也是不满足if条件,进入for循环,startIndex为1,截取字符串aab的第二个字母a,为回文串,isValid返回true,将其放入path中,path为[a, a],递归进入下一个backtracking,startIndex为2,截取字符串aab的最后一个字母b,为回文串,isValid返回true,将其加入到path中,path为[a, a, b],递归进入下一个backtracking中,startIndex为3,满足if条件,因此将[a, a, b]放入ans集合中,递归返回上一个backtracking,将字符串b从path中移除,path为[a, a],for循环继续,i++,i等于3,等于字符串长度,for循环结束,递归返回上一个backtracking,将字符串a从path中移除,path为[a],for循环继续,i++,截取字符串aab中最后两个字母ab,不是回文串,isValid返回false,for循环继续,i++,等于字符串长度,for循环结束,递归返回最初的backtracking,将字母a从path中移除,path为空,for循环继续,i++,截取字符串aab中的前两个字母aa,为回文串,isValid为true,将aa放入path中,递归进入下一个backtracking,startIndex为2,截取最后一个字母b,为回文串,isValid为true,将字母b加入path中,path为[aa, b],递归进入下一个backtracking,startIndex为3,满足if条件,将[aa, b]加入ans集合中,递归返回上一个backtracking,将b从path中移除,path为[aa],for循环继续,i++后等于3,for循环结束,递归返回最初的backtracking,将aa从path中移除,for循环继续,i++,此时截取了整个字符串aab,显然不是回文串,isValid为false,for循环继续,i++后等于3,for循环结束,递归返回到partition,返回ans。
在上述回溯代码中,关键部分在于使用了一个startIndex参数,规定了下一个递归截取的起始位置为当前递归方法遍历位置i的下一个位置i+1,需要注意的是,substring字符串截取方法截取区间是左闭右开,包含左侧,不包含右侧,因此要截取当前遍历位置i,右侧区间端点需要为i + 1。