没接触过回溯算法,第一次遇见有点模糊的感觉,需要多加练习
2023.4.7 组合
没有进行剪枝操作的代码。
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
backTracking(n,k,1);
return res;
}
public void backTracking(int n,int k,int start){
if(path.size() == k){
res.add(new ArrayList(path));
return;
}
for(int i = start;i <= n;i++){
//path路径还没有满足要求,直接放入path中
path.add(i);
//进入递归,这里start需要+1,是因为我们放入的值时不能重复的;
backTracking(n,k,i+1);
//退出递归,代表我们的path长度已经满足了要求,此时需要减去最后一个元素,重新放入新的元素
path.removeLast();
}
}
}
我们其实可以发现如果start到末尾的位置元素个数少于了k,其实就没有意义了,不需要再对其进行统计,因此可以对这部分内容进行优化。
例子:假设n=7,k=4,那么从5开始搜索就没有意义了,因此我们的start的搜索起点是存在一个小于n的界限的,
即搜索起点的上界+接下来要选择的元素个数-1 = n
而我们接下来要选择的元素个数 = k-path.size()
因此我们搜索起点的上界 = n-(k-path.size())+1
因此我们的for循环判断关系就从i < n变为了 i < n - ( k - path.size()) + 1
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
backTracking(n,k,1);
return res;
}
public void backTracking(int n,int k,int start){
if(path.size() == k){
res.add(new ArrayList(path));
return;
}
for(int i = start;i <= n - ( k - path.size()) + 1;i++){
//path路径还没有满足要求,直接放入path中
path.add(i);
//进入递归,这里start需要+1,是因为我们放入的值时不能重复的;
backTracking(n,k,i+1);
//退出递归,代表我们的path长度已经满足了要求,此时需要减去最后一个元素,重新放入新的元素
path.removeLast();
}
}
}