组合
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 28 ms, 内存: 17.4 MB
/*
* 思路:虽然Java Stream不是最适合回溯算法的工具,但我们可以使用组合的方式来生成所有可能的组合。
* 这里我们使用一个辅助函数来生成组合并转换为流。
*/
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class SolutionStream {
public List<List<Integer>> combine(int n, int k) {
return combineHelper(IntStream.rangeClosed(1, n).boxed().collect(Collectors.toList()), k);
}
private List<List<Integer>> combineHelper(List<Integer> nums, int k) {
if (k == 0) {
List<List<Integer>> result = new ArrayList<>();
result.add(new ArrayList<>());
return result;
}
if (nums.isEmpty()) return new ArrayList<>();
int head = nums.get(0);
List<Integer> rest = nums.subList(1, nums.size());
List<List<Integer>> excludingHead = combineHelper(rest, k);
List<List<Integer>> includingHead = combineHelper(rest, k - 1).stream()
.peek(list -> list.add(0, head))
.collect(Collectors.toList());
List<List<Integer>> result = new ArrayList<>(excludingHead);
result.addAll(includingHead);
return result;
}
}
解释
方法:
这个解决方案使用了回溯法来找出所有可能的k个数的组合。首先,定义一个递归函数fun,它从1到n逐个尝试添加数字到当前组合ans中。如果当前组合的长度到达k,就将其复制后添加到结果列表count中。如果组合未完成,函数继续递归尝试当前数字i的下一个数字i+1。此外,函数在尝试每个数字后,都会将其从组合中移除(回溯),然后尝试下一个数字。此解法还包含一个剪枝的优化:如果当前可选的数字数量小于所需的数量,就提前终止递归。
时间复杂度:
O(2^n)
空间复杂度:
O(n + k)
代码细节讲解
🦆
在递归函数`fun`中,你提到了剪枝的优化,能详细解释一下这种剪枝是如何工作的,以及它为什么能提高效率吗?
▷🦆
递归函数`fun`中有两个递归调用的地方,一个是在添加了当前数字到组合`ans`后,另一个是在`ans`弹出当前数字后,这个过程如何确保不会重复生成相同的组合?
▷🦆
你提到递归的最大深度为`n`,这是怎么确定的?为什么不是`k`,即组合的大小?
▷