将题目转化为递归树的问题。
用一个List装载回溯的值,当一个回溯到达底层时候,用一个List去装载回溯的值,每次重新回溯的时候都要注意,当你重新回溯时候,一定一定要把List中值取消掉,也就是说回溯算法需要取消掉自己的操作。
1.步骤,用一个List<List> res装载返回值
用一个List跟着节点去遍历,遍历成功后,将路径值加进去,当到底的时候,也就是list值等于数组长度时候,到底了。到底就记得要回溯
回溯和递归回去有一个本质区别‘
就像月光宝盒一样,你必须撤除自己做过的操作。’
回溯算法的本质是题目让我们找全所有解法。
每次传递数值时候把数组传递进去就行了,然后控制一下start和end
记住比自己小的值不能传递进去。
每次传递这个数组就行了
本质就是递归加遍历,在每一层数组中多次调用递归,多次进行遍历。
class Solution {
public List<List<Integer>> combine(int n, int k) {
//前面的数不能大于后面的数
//用一个List<List<Integer>>返回数
int[] num = new int[n];
for(int i = 0;i < n;i++){
num[i] = i + 1;
}
List<List<Integer>> res = new ArrayList<>();
//用来存数值
LinkedList<Integer> path = new LinkedList<>();//返回中间值
for(int i = 0;i < num.length;i++){
//从这里就是多重递归,开始递归之旅
dfs(num,res,i,path,k);
path.pollLast();
}
return res;
}
//不需要返回值,每次都传递res和path就行
public void dfs(int[] num,List<List<Integer>> res,int start,LinkedList<Integer> path,int k){
path.add(num[start]);//进了循环就将数据加入路径
//我们用一个对象传递数据,所以不用担心返回值问题
//返回终止条件
if(path.size() == k){
//路径值大小等于K返回
res.add(new LinkedList(path));//将path的值放进去,不能放地址,这步相当于复制了path的值
return;
}
for(int i = start;i < num.length - 1;i++){
//回溯算法是递归和循环相结合
dfs(num,res,i + 1,path,k);
path.pollLast();//把尾巴弹出来撤销自己上次的选择
}
}
}
我这个方法,可以做,但是很蠢逼,相当于
在主函数里搞了个for循环遍历
在dfs子函数里也搞了个for循环遍历,全都是因为一个问题
那就是在一进dfs时候,就把当前节点加入路径了,这样
这个for循环就影响不到节点加入路径这个问题了。
正确降低代码量的方式应该是,将path.add()这个操作放到for循环里去,这样第一次操作时候{1,2,3,4}整个数组都会被作为选择。
class Solution {
public