回溯算法
回溯算法 (backtracking),回退/撤销到上一步;
like 棋盘摆放问题有时候会做的剪枝/裁剪 (pruning)
all 回溯算法都可以变成一个树的结构
常见回溯问题:
- 组合问题:N个数里面按一定规则找出k个数的集合
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 排列问题:N个数按一定规则全排列,有几种排列方式
- 棋盘问题:N皇后,解数独等等
回溯算法模板
通过递归去控制嵌套for 循环
的个数,like 要在[1, n]
中找出all 2个数的组合,需要2个for循环,但如果要找到10个数的组合,用暴力一直写 for循环 就不行了
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
leetcode 77
题目链接
找所有组合,非排列, ∴ \therefore ∴[1, 2]
和[2, 1]
是相同的
思路:
- 首先确定递归的返回值(一般都是
void
),参数 - 确定递归的终止条件
- 确定
for循环
中的逻辑
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
combineHelper(n, k, 1);
return res;
}
public void combineHelper(int n, int k, int index){
if (path.size() == k){
res.add(new ArrayList<>(path));
return;
}
for (int i = index; i <= n - (k - path.size()) + 1; ++i){
path.add(i);
combineHelper(n, k, i + 1);
path.removeLast();
}
}
}