-
首先要定义结果集合res和判断集合长度的队列path,写终止条件,然后进入递归函数,最后返回结果集res
-
递归函数部分:首先写终止条件,在什么条件下将结果集进行保存?res.add(new ArrayList<>(path));
-
然后是回溯的模板如下:
for循环横向选择{
进行操作(path.addLast(i))
然后递归
最后要撤销之前的操作path.removeLast()
}
优化方法:对上述的方法进行剪枝 —> 分析搜索起点的上界进行剪枝
搜索起点的上界 + 接下来要选择的元素个数 - 1 = n
其中,接下来要选择的元素个数 = k - path.size(),整理得到:
搜索起点的上界 = n - (k - path.size()) + 1
就是把 i <= n 改成 i <= n - (k - path.size()) + 1 : -
二刷:对关键位置进行剪纸,主要的作用就是避免多选元素(即避免path.size() 长度超出k 之后,还会进行判断)通过这样设定,可以限定在最长的位置结束。
class Solution {
List<List<Integer>> res = new ArrayList<>();
Deque<Integer> path = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
if(n < k) return res;
recur(n, k, 1);
return res;
}
public void recur(int n, int k, int begin){
if(path.size() == k){
res.add(new ArrayList<>(path));
return;
}
for(int i = begin; i <= n - (k - path.size()) + 1; i++){
path.addLast(i);
recur(n, k, i + 1);
path.removeLast();
}
}
}
class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
//首先写终止条件,当。。。。
if (k <= 0 || n < k) {
return res;
}
// 从 1 开始是题目的设定
//定义一个队列path
Deque<Integer> path = new ArrayDeque<>();
dfs(n, k, 1, path, res);
return res;
}
//如下是递归函数 题目要求是返回范围从1开始,然后定义队列path 和 结果集合 res
private void dfs(int n, int k, int begin, Deque<Integer> path, List<List<Integer>> res) {
// 递归终止条件是:path 的长度等于 k
if (path.size() == k) {
//当以上条件满足的时候,将此时的path加入到res中
res.add(new ArrayList<>(path));
return;
}
// 遍历可能的搜索起点
for (int i = begin; i <= n; i++) {
// 向路径变量里添加一个数
path.addLast(i);
// 下一轮搜索,设置的搜索起点要加 1,因为组合数理不允许出现重复的元素
dfs(n, k, i + 1, path, res);
// 重点理解这里:深度优先遍历有回头的过程,因此递归之前做了什么,递归之后需要做相同操作的逆向操作
path.removeLast();
}
}
}
//对上述的方法进行剪枝 ---> 分析搜索起点的上界进行剪枝-----------------------------
//对上述的方法进行剪枝 ---> 分析搜索起点的上界进行剪枝-----------------------------
//对上述的方法进行剪枝 ---> 分析搜索起点的上界进行剪枝-----------------------------
//对上述的方法进行剪枝 ---> 分析搜索起点的上界进行剪枝-----------------------------
class Solution {
/**
*/
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
if(k <= 0 || n < k){
return res;
}
Deque<Integer> path = new ArrayDeque<>();
dfs(n, k, 1, path, res);
return res;
}
//如下是递归函数 题目要求是返回范围从1开始,然后定义队列path 和 结果集合 res
private void dfs(int n, int k, int begin, Deque<Integer> path, List<List<Integer>> res){
if(path.size() == k){
res.add(new ArrayList<>(path));
return;
}
// 搜索起点的上界 + 接下来要选择的元素个数 - 1 = n
// 其中,接下来要选择的元素个数 = k - path.size(),整理得到:
// 搜索起点的上界 = n - (k - path.size()) + 1
// 把 i <= n 改成 i <= n - (k - path.size()) + 1 :
for(int i = begin; i <= n -(k - path.size()) + 1; i++){
path.addLast(i);
dfs(n, k, i + 1, path, res);
path.removeLast();
}
}
}