题目简述:1-n 个数字里面, 选出 k 个来,元素不能重复使用,列出所有的情况,也就是C(n,k)种情况
和216题,也没啥不同就是
思路解析
我们可以使用回溯算法来解决这个问题。回溯的核心就是“选择 + 递归 + 撤销选择”,这在组合类问题中是一种非常常见且高效的模式。
关键点有两个:
- for 循环中的
start参数是剪枝的关键之一:
我们只从当前数字往后枚举,避免重复和无效搜索。 - 每次递归中都判断长度是否为 k,如果是,就将当前组合加入结果中。
var combine = function (n, k) {
// n 个数字选 k 个
let res = []
var backtrack = function (start, one) {
if (one.length === k) {
res.push([...one])
return
}
for (let i = start; i <= n; ++i) {
one.push(i)
backtrack(i + 1, one)
one.pop()
}
}
backtrack(1, [])
return res
};
关于剪枝优化
我们这里的剪枝操作体现在两个地方:
- 起始位置
start控制了数字不能重复使用且避免重复组合(比如[1,2]和[2,1]是同一个组合,应该只出现一次)。 - 若想更进一步地优化,还可以添加如下剪枝判断,减少递归层数:
for (let i = start; i <= n - (k - one.length) + 1; ++i)
这个优化确保了在剩余数字不足以组成 k 个数时就不再递归,节省不必要的搜索。
小结
- 回溯模板在组合类题目中非常通用。
- 灵活控制
start参数和使用path.pop()回退,是解决该题的关键。 - 216题,和这题比较像,只需要去掉一些和“求和”相关的逻辑即可。