题目描述:
标签:回溯算法
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
代码:
思路分析:
1、确定递归结束条件,path.size==k
2、确定从左到右遍历,需要开始下标startIndex
3、确定从上到下遍历,需要递归操作
4、确定回溯条件,需要清除path里的元素
这里需要注意的一点是不能写成result.add(path),要写成result.add(new ArrayList<Integer>(path)),网上的解释:add(path),我们这是将path的地址给add进去了,并没有将真正的列表add进热resultlist,这样导致的结果就是 当你的path中的值改变后,resultlist中也随之改变,楼主不出意外的话,你最后的path变为空了,所以最后输出全空。
一:剪枝前:
class Solution {
List<List<Integer>> result = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<Integer>();
public List<List<Integer>> combine(int n, int k) {
backtracing(n,k,1);
return result;
}
public void backtracing(int n,int k,int startIndex){
if(path.size() == k){
result.add(new ArrayList<Integer>(path));
return;
}
for(int i = startIndex;i <= n ;i++){
path.add(i);
backtracing(n,k,i+1);
path.remove(path.size()-1);
}
}
}
二:剪枝后:
思路分析:
比如说n=4,k=4,其实只能是起始下标为1可以检索到,从2,3,4开始剩下的元素都不足4个根本不满足条件,所以需要对startIndex进行校验从而实现剪枝操作!
效率提高不少,不剪枝是28ms,剪枝是2ms
class Solution {
List<List<Integer>> result = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<Integer>();
public List<List<Integer>> combine(int n, int k) {
backtracing(n,k,1);
return result;
}
public void backtracing(int n,int k,int startIndex){
if(path.size() == k){
result.add(new ArrayList<Integer>(path));
return;
}
for(int i = startIndex;i <= n - (k - path.size()) + 1;i++){
path.add(i);
backtracing(n,k,i+1);
path.remove(path.size()-1);
}
}
}