回溯算法模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
组合问题
1.与for循环相比,回溯法优势在于可以用递归控制for循环嵌套的数量
2.for循环横向遍历,递归纵向遍历。for循环参数i取值范围控制剩余集合,递归返回条件控制树形图深度。
3.优化回溯算法:剪枝,常用:在for循环终点进行剪枝或根据题意如总和进行剪枝。
4.什么时候需要startIndex?一个集合求组合。
如果是多个集合取组合,各个集合之间相互不影响,则不需要startIndex。
5.树枝去重与树层去重:结果集不可有重复,使用树层去重;每个结果不可有重复,使用树枝去重。
6.注意输入异常的情况。
切割问题
1.本质:转成组合问题,切割线使用startIndex,子串范围为nums[startIndex,i]
子集问题
1.子集问题收集所有节点的结果,组合问题收集叶子节点的结果。
result.add(new ArrayList<>(path));//收集子集,要放在终止添加的上面,否则会漏掉结果。
if(startIndex>=nums.length()){
return;
}
2.子集问题去重依然采用组合问题去重的那两个思路。要注意,去重方式目前了解的一个是对数组进行排序之后使用used数组,另一种方式是使用hashset。两者区别第二种更普遍,第一种只能用于原数组可以被重新排序的情况。
3.递增子序列:子集问题一定要排序,画树形图即可了解。
排列问题
1.不需要使用startIndex,每个for循环都是从0开始。
2.使用used数组记录path都放了什么元素。
去重问题
1.使用hashset效率更低,因为哈希映射更费时间。