找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
只使用数字 1 到 9 每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。
示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。
示例 3:
输入: k = 4, n = 1
输出: []
解释: 不存在有效的组合。
在[1,9]范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。
提示:
- 2 <= k <= 9
- 1 <= n <= 60
思路:
- 回溯函数:定义一个深度优先搜索(DFS)函数 dfs,它尝试在当前位置添加一个数字,并递归地尝试添加下一个数字。
- 剪枝:在 dfs 函数中,通过剪枝来减少不必要的搜索。如果当前组合的长度加上剩余数字的数量不足以达到 k,则没有必要继续搜索。同样,如果组合长度已经超过 k,也直接返回。
- 检查和:当组合长度达到 k 且组合的和等于 n 时,将当前组合添加到结果数组 res 中。
- 递归搜索:在 dfs 函数中,先尝试添加当前数字,然后递归地调用 dfs 函数尝试添加下一个数字。之后,回溯(即删除当前数字),尝试不添加当前数字的情况。
- 初始化和调用:初始化一个空数组 temp 来存储当前组合,一个空数组 res 来存储所有有效组合。然后调用 dfs 函数开始搜索。
时间复杂度:最坏情况下是 O(2^9),因为对于每个数字,你可以选择包含或不包含它,总共有 9 个数字。然而,由于剪枝的存在,实际的时间复杂度会小于这个上界。
空间复杂度:O(k),这是因为在最坏的情况下,递归栈的深度可以达到 k,同时 temp 数组最多包含 k 个元素。
var combinationSum3 = function (k, n) {
const temp = [];
const res = [];
const dfs = (cur, n, k, sum, res) => {
if (temp.length + (n - cur + 1) < k || temp.length > k) {
return;
}
if (temp.length === k && temp.reduce((previous, value) => previous + value, 0) === sum) {
res.push(temp.slice());
return;
}
temp.push(cur);
dfs(cur + 1, n, k, sum, res);
temp.pop();
dfs(cur + 1, n, k, sum, res);
};
dfs(1, 9, k, n, res);
return res;
};