下文承接
一. 简单介绍
1. 回溯算法简单介绍
回溯算法是基于递归函数之上的,本质是穷举所有可能符合答案的选项。和一般递归最大的区别是,本身带有撤销这一明显特征,即选择,递归,然后返回,撤销。虽然可以加一些剪枝的操作,但本身算法时间复杂度很高,没有改变穷举的本质。
回溯算法主要解决排列,组合,子集类的问题 [1]。
2. 回溯算法一般模板
public void dfs(参数1,参数2,...,参数n){
//终止条件
if(){
//添加答案
return;
}
//遍历所有可能选项
for(int i = ?; i < ?; i++){
//添加操作
dfs()
//撤回操作,和有可能的第二次dfs()
dfs()
}
}
3. 回溯算法的树型转换
回溯算法可以用树来转换,树的深度遍历即DFS可以理解为向下的递归,for循环内可以理解为对所有的可能性的排查,是对本层的遍历。
以leetcode77中为例,那么对数型结构的转换为:
以树形结构来思考,可以更具体地抽象出递归的过程,也会方便剪枝。
二. leetcode实战
1. 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>> ans = new ArrayList<>();
public List<List<Integer>> combine(int n, int k) {
List<Integer> path = new ArrayList<>();
dfs(1,n,k,path);
return ans;
}
public void dfs(int index, int n, int k , List<Integer> path){
if(path.size() == k){
ans.add(new ArrayList<Integer>(path));
return;
}
for(int i = index; i <= n; i++){
path.add(i);
dfs(i+1, n , k, path);
path.remove(path.size() - 1);
}
}
}
本题小结:
本题是经典的回溯问题,要注意的点有:(1)ans.add()中要生成一个新的list
(2)dfs(i+1, n , k, path)中是i还是index
(3)index产生12组,i产生6组
回溯剪枝:
观察n=4,k=3的情况,以树形结构给出图: