回溯代码的模板:
void backTracking(参数){
if(满足条件/终止条件){
存放结果;
return;
}
for(选择:本层集合中元素(树种节点孩子的数量就是集合的大小)){
处理节点;
backTracking(参数);
回溯,撤销处理;
}
}
做这类题目要将多叉树和for以及一些条件结合。
for就相当于跟节点的所有情况;处理节点就是这个边上的处理动作,在这个节点上就是backTracking内部参数的结果,之后就是回溯,撤销处理。
LeetCode77组合
class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> ans = new ArrayList<>(); // 这里最好携程全局变量,因为这些数据是需要改变的,放在这个函数里面就必须将其传入到递归函数的参数里面,容易混淆。
LinkedList<Integer> temp = new LinkedList<>();
backTracking(n, k, ans, temp, 1);
return ans;
}
public void backTracking(int n, int k, List<List<Integer>> ans, LinkedList<Integer> temp, int startIndex){ // 注意参数
if(temp.size() == k){ // 终止条件 当集合大小达到k就表示找到一个 立马返回 并加到ans里
ans.add(new LinkedList<>(temp));
return;
}
// 使用了一个startIndex标记当前选择到哪一个数,递增,前面的数就不选了。实现找到集合的功能,不然会把所有的都找到
for(int i=startIndex;i<=n;i++){
temp.add(i); // 先加到temp里面做记录
backTracking(n,k,ans,temp,i+1); // 递归找下一个数,
temp.removeLast(); // 回溯,删除上一个添加的最后一个数,以便找到下一个。
}
}
}
class Solution {
private:
void backTracking(int n, int k, int startIndex, vector<int>& temp, vector<vector<int>>& ans){
// 注意传递的大型对象时,使用引用或者指针
if(temp.size() == k){
ans.push_back(temp);
return;
}
if(temp.size() + (n - startIndex + 1) < k){
return;
} // 这里就是剪枝的操作,让一些在for循环中压根不会有结果的分支,直接剔除。
for(int i=startIndex;i<=n;i++){
temp.push_back(i);
backTracking(n,k,i+1,temp,ans);
temp.pop_back();
}
};
public:
vector<vector<int>> combine(int n, int k) {
vector<int> temp;
vector<vector<int>> ans;
backTracking(n,k,1,temp,ans);
return ans;
}
};