提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
所有回溯法的问题可以抽象为树形结构,因为回溯法解决的就是在集合中递归查找子集。
集合的大小构成数的宽度,递归的深度构成数的深度
一、回溯法模板三部曲
-
回溯函数模板返回值以及参数
回溯算法中的函数返回值去我们一般为void
再来看⼀下参数,⼀ 般是先写逻辑,然后需要什么参数,就填什么参数。
-
回溯函数终⽌条件
我们再来看一下参数,我们首先需要先理清逻辑,确定我们需要什么参数,就添加什么参数我们都知道递归算法我们必须要设置终止条件,否则这就是一个死循环。所以回溯算法同时也需要终止条件
if(终止条件){
存放条件;//即根据题目要求设置存放条件
return;
}
-
回溯搜索的遍历过程
我们提到过,回溯法就是在集合中递归查找子集。集合的大小构成数的宽度,递归的深度构成数的深度
for (选择:本层集合中元素(树中节点孩⼦的数量就是集合的⼤⼩)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
即:for循环横向遍历,backtracking(递归)纵向遍历
回溯算法的整体框架如下:
public void backtracking(){
if(终止条件){
存放结果;
return;
}
for(横向遍历,遍历节点数目大小等于集合的大小){
处理节点;//即纵向遍历(递归遍历)
backtracking(路径,列表选择);//
回溯,撤销处理结果 //回溯法的关键
}
}
二、回溯实例
组合问题--77.组合
题目来自leetcode 题库,题号77
题目要求
给定两个整数 n
和 k
,返回范围 [1, n]
中所有可能的 k
个数的组合。
你可以按 任何顺序 返回答案。
示例:
输入:n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
充分利用上面的模板,带入题目的要求。
class Solution {
List<List<Integer>> result = new ArrayList<>();//用来存放符合条件结果的集合
LinkedList<Integer> temp = new LinkedList<>(); //用来存放符合条件的单一结果
public List<List<Integer>> combine(int n, int k) {
combineHelper(n,k,1);
return result;
}
public void combineHelper(int n,int k,int startIndex){
//startIndex代表
if(temp.size() == k){ //即 temp的长度 满足题目要求
result.add(new LinkedList<>(temp));
return;
}
for(int i = startIndex ;i <= n - (k - temp.size()) + 1;i++){控制数的横向遍历
temp.add(i);//处理节点
combineHelper(n,k,i + 1);//递归:控制数的纵向遍历,注意下一次搜索应该从i+1开始了
temp.removeLast();//回溯,撤销处理的节点
}
}
}
总结
回溯算法的组合问题刚开始可能会有点难,但是它有明显的规律,所以模板很重要!!有了这个模板,就有解题的⼤体⽅向,熟悉过后就可以初步了解回溯的组合问题了。
如果你还是对回溯问题不太清楚的话,推荐关注代码随想录公众号,里面有对回溯算法的详细讲解