一、回溯
回溯法的思想是:通过枚举,对所有的可能进行遍历。但是枚举是一直枚举到最后一个元素,发现走不通,再回退一步,枚举没有走过的元素。回溯的关键在于:走不通就回退一步。
回溯的实现:for循环+递归
解释如下:for循环就像一个路径选择,递归返回之后就相当于回退一步。例如第一次选择第一条路径,i = 0,进入该条路径,递归方法完成后返回,相当于回退到初始点,然后进入下一次循环。
二、回溯模板
public backward(){
if(回退点){
//这条路的结束点
save();
return;
}else{
//剪枝
if(不满足){
return;
}else{
//从当前路径开始,继续遍历下一个元素
dfs(...);
}
}
}
三、组合总和
1、所有元素都可以被无限使用,则每次递归都要从当前元素开始寻找路径
for(int i = curIndex; i < candidates.length; i++)
2、单条路径的实现:new ArrayList<Integer>(),作为dfs的参数进入递归,每次递归结束后进行回溯操作
3、代码部分
import java.util.ArrayList;
import java.util.List;
public class CombinationSum {
public static List<List<Integer>> res;
public static void main(String[] args) {
System.out.println(combinationSum(new int[]{2,3,6,7},7));
}
public static List<List<Integer>> combinationSum(int[] candidates, int target) {
res = new ArrayList<>();
dfs(candidates,target,0,new ArrayList<>());
return res;
}
public static void dfs(int[] candidates,int target,int index,List<Integer> list){
if(target == 0){
res.add(new ArrayList<>(list));
return;
}
if(target < 0){
return;
}
for(int i = index; i < candidates.length; i++){
list.add(candidates[i]);
dfs(candidates,target - candidates[i],i,list);
list.remove(list.size()-1);
}
}
}
4、dfs优化
如果在进入递归前就能判断当前路走不通,就减少了递归调用dfs次数,减少运行时间。
public static void dfs(int[] candidates,int target,int index,List<Integer> list){
if(target == 0){
res.add(new ArrayList<>(list));
return;
}
for(int i = index; i < candidates.length; i++){
if(target - candidates[i] < 0) break;
list.add(candidates[i]);
dfs(candidates,target - candidates[i],i,list);
list.remove(list.size()-1);
}
}