LeetCode 131. 分割回文串
131. 分割回文串 - 力扣(LeetCode)
什么是回溯算法?
回溯算法真的是解决排列问题的一大利器,其实很多时候自己不经意间就写出了回溯算法,但是一直没有一个系统的认识,今天做一个详细的总结。
概念:回溯法(back tracking)(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回到上一步,重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为 “回溯点”。
回溯法和穷举法很像,不如说回溯法是穷举法的一个改进,它在所有可行的选择中,系统地搜索问题的解。它假定解可以由向量形式 ( x 1 , x 2 , . . . , x n ) (x_1,x_2,...,x_n) (x1,x2,...,xn)来表示,其中 x i x_i xi 的值表示在第 i i i 次选择所作的决策值,并以深度优先的方式遍历向量空间,逐步确定 x i x_i xi 的值,直到解被找到。
所以在使用回溯法时,需要在脑中形成一棵解空间构成的树
- 当我们要解决的问题是要求一个使问题最优的n个元素的子集,问题的解空间常可以组织成一棵子集树
- 当问题是求n个元素一个排列以使问题最优化时,解空间常可以组织成一棵排列树。
看到这里会发现,回溯法又和二叉树地深度优先搜索很像,其实具有界限函数的深度优先搜索法又称为回溯法,这里的界限函数又称为剪枝函数
- 利用剪枝函数,剪除无用的分支,集中搜索最有用的分支,提高搜索效率
- 其实就是根据已有条件判断还要不要继续向下搜索了,如果当前条件已经不成立了,当然也没有必要继续搜索了。
回溯算法设计步骤:
- 回溯函效
- 结束条件
- 结果添加
- 返回操作
- 可选选择
- 剪枝操作
- 路径添加
- 下一节点
- 路径回溯
回到本题
利用回溯算法的思想就很好分析了,可以像切面剂子一样,把字符串一个个切开,每次截取都判断已经切好的部分是否都是回文子串就行了
class Solution {
List<List<String>> res;
public List<List<String>> partition(String s) {
res = new ArrayList<>();
if (s.length() == 1) {
List<String> list = new ArrayList<>();
list.add(s);
res.add(list);
return res;
}
List<String> list = new ArrayList<>();
process(s, 0, list);
return res;
}
public void process(String s, int startIndex, List<String> list) {
if (startIndex == s.length()) {
res.add(new ArrayList<>(list));
return;
}
for (int i = startIndex + 1; i <= s.length(); i++) {
String sub = s.substring(startIndex, i);
if (!isPalindrome(sub)) {
continue;
}
list.add(sub);
process(s, i, list);
list.remove(list.size() - 1);
}
}
/**
* 判断是否是回文串
* @param sub 子串
* @return 是否是回文串
*/
private boolean isPalindrome(String sub) {
int left = 0;
int right = sub.length() - 1;
while (left < right) {
if (sub.charAt(left) != sub.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
}