回溯理论基础
回溯:回溯搜索法,本质就是暴力搜索,效率并不高
回溯法解决的问题
回溯法,一般可以解决如下几种问题:
- 组合问题:N个数里面按一定规则找出k个数的集合
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 排列问题:N个数按一定规则全排列,有几种排列方式
- 棋盘问题:N皇后,解数独等等
回溯算法模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
组合问题
题目链接:
这段Java代码定义了两个静态函数dfs和combine以及两个静态变量res和list。其中,res是一个存储结果的二维列表,list是一个临时列表,用于存储当前组合的数字。
dfs函数通过深度优先搜索的方式生成所有长度为k的组合,这些组合由1到n之间的数字构成。函数的参数包括k(组合的长度)、n(数字的上限)和start(当前搜索的起始数字)
代码:
class Solution {
public List<List<Integer>> res = new ArrayList<>();
public List<Integer> list = new ArrayList<>();
public void dfs(int k, int n, int start) {
if (list.size() == k) {//当list的大小大于k,说明已经搜集了k个结果
res.add(new ArrayList<>(list));
return ;
}
for (int i = start; i <= n ; i++) {//对1-n进行遍历
list.add(i);
dfs(k, n, i + 1);//向下一个位置递归
list.remove(list.size() - 1);//回溯
}
return ;
}
public List<List<Integer>> combine(int n, int k) {
dfs(k,n,1);
return res;
}
}
剪枝优化:
for (int i = start; i <= n - (k - list.size()) + 1; i++) {
list.add(i);
dfs(k, n, i + 1);
list.remove(list.size() - 1);
}