秋招-算法-回溯算法篇
介绍
回溯实际上是一种试探算法,这种算法跟暴力搜索最大的不同在于,在回溯算法里,是一步一步地小心翼翼地进行向前试探,会对每一步探测到的情况进行评估,如果当前的情况已经无法满足要求,那么就没有必要继续进行下去,也就是说,它可以帮助我们避免走很多的弯路。
回溯算法的特点在于,当出现非法的情况时,算法可以回退到之前的情景,可以是返回一步,有时候甚至可以返回多步,然后再去尝试别的路径和办法。这也就意味着,想要采用回溯算法,就必须保证,每次都有多种尝试的可能。
模板
下面的去重、做剪枝弄不出来,可以直接用set或者List的contain等方法在返回结果前处理下,效率会下降,但至少能对点
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
trim,去重、做剪枝
choose,选择合适的结果
backtrack(路径, 选择列表)
back,撤销选择
常见类型为全排列和组合两种:
在【for 选择 in 选择列表】这步骤上为主要区别,全排列一般是从头开始遍历,而组合一边是接着上次的接口开始遍历
例题
47. 全排列 II
class Solution {
List<List<Integer>> res;
public List<List<Integer>> permuteUnique(int[] nums){
res = new LinkedList<>();
Arrays.sort(nums);
boolean[] used = new boolean[nums.length];
backtrace(nums,new LinkedList<>(),used);
return res;
}
private void backtrace(int[] candidates,LinkedList<Integer> chain,boolean[] used) {
//base
if (chain.size()==candidates.length){
res.add(new LinkedList<>(chain));
return;
}else if (chain.size()>candidates.length){
return;
}
//for
for (int i = 0; i < candidates.length; i++) {
//trim
//112 ==> 112 211 211
if (used[i]) continue;
if (i>0&&candidates[i]==candidates[i-1]&&!used[i-1]) continue;
//choose
chain.add(candidates[i]);
used[i]=true;
backtrace(candidates,chain,used);
//back
chain.removeLast();
used[i]=false;
}
}
}
40. 组合总和 II
class Solution {
List<List<Integer>> res;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
res = new LinkedList<>();
Arrays.sort(candidates);
backtrace(target,candidates,0,new LinkedList<>(),0);
return res;
}
private void backtrace(int target, int[] candidates,int sum,LinkedList<Integer> chain,int pos) {
//base
if (sum==target){
res.add(new LinkedList<>(chain));
return;
}else if (sum>target){
return;
}
//for
for (int i = pos; i < candidates.length; i++) {
//trim
//加入给了 1,1,6,7 target=8 , ==> 可以选择: 116 ,有两个1要对两个1,7去重
//116 是通过回溯递归获得的第二个1
//17 17,是通过for循环获得的第二个1
//循环会造成i>pos,回溯递归i=pos,借此进行剪枝、去重
if (i>pos&&candidates[i]==candidates[i-1]){
continue;
}
//choose
chain.add(candidates[i]);
backtrace(target,candidates,sum+candidates[i],chain,i+1);
//back
chain.removeLast();
}
}
}