代码随想录算法训练营第二十四天|回溯理论基础、77.组合
理论基础:
- 什么是回溯算法:回溯算法也可以叫做回溯搜索法,只要有递归,就会有回溯。
回溯的本质是穷举,穷举所有可能,找到我们的答案,也就是暴力搜索。
- 回溯法能解决的问题:
- 组合问题:(无序)N个数里面按一定规则找出k个数的集合
- 排列问题:(有序)N个数按一定规则全排列,有几种排列方式
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 棋盘问题:N皇后,解数独等
- 如何理解回溯算法
回溯算法的解决问题都可以抽象成树形结构,因为回溯算法解决的问题都是在接种递归查找子集,集合的大小构成了数的宽度,递归的深度,构成了树的深度。
递归就要有终止条件,所以是一棵高度有限的树。
- 回溯模板
- 回溯模板的返回值及参数
返回值一般是void,先写逻辑,需要什么参数再写。
void backtracking(参数)
- 回溯终止条件
搜索到叶子节点,也就找到了满足条件的一条大难,将这个答案保存起来,结束本层递归
if(终止条件){
存放结果;
return;
}
-
回溯遍历过程
在集合中递归搜索,用for横向遍历,然后递归纵向遍历
for(选择:本层集合中的元素(树中节点孩子的数量就是集合的大小)){
处理节点;
backtracking(路径,选择列表);
回溯,撤销处理结果;
}
模板总结:
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
回溯算法需要注意剪枝过程。
77.组合
给定两个整数 n
和 k
,返回范围 [1, n]
中所有可能的 k
个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
题解:回溯算法也是一个暴力搜索的过程,模拟嵌套for循环。它是怎么做到的呢?通过递归来控制有多少层for循环,递归一层就是一个for循环。回溯叶子节点就是结果。
代码:
class Solution {
List<List<Integer>> res=new ArrayList<>();
List<Integer> path=new ArrayList<>(); //存放每一条路径,这个是递归多少层的
public List<List<Integer>> combine(int n, int k) {
backTracking(n,k,1);
return res;
}
//回溯算法
public void backTracking(int n,int k,int index){ //index是从哪个位置开始搜索,控制横向
//终止条件
if(path.size()==k){ //找到了符合条件的集合
res.add(new ArrayList<>(path));
return;
}
//单层逻辑 for循环
for(int i=index;i<=n;i++){
path.add(i);
backTracking(n,k,i+1);
path.removeLast();
}
}
}