难度中等
找出所有相加之和为 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
分析:从 1 ~ 9 内选取出 k 个相加和为 n 的数,首先确定回溯算法的递归函数的参数和返回值,在去确认终止条件和单层搜索过程。
解题过程:
- 首先肯定需要个集合来存放符合条件的结果和最终返回的结果集
输入: 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
没有其他符合的组合了。
通过示例可以看出最后的结果是个二维数组,那肯定需要一个一维数组存放每一次符合条件的组合,另外一个二维数组存放所有符合条件的结果集。
vector<int> path; // 符合条件的结果
vector<vector<int>> res; // 存放结果集
- 确认递归函数的参数和返回值
一般情况下回溯算法中递归函数是没有返回值,除非遇到了特殊情况。所以本题我们只需要确认函数的参数,n 和 k 肯定是需要的,还需要一个 sum 存放 path 元素里的总和于 n 做对比是否相等,一个 startIndex 来确定下一次循环的起始位置。
vector<int> path; // 符合条件的结果
vector<vector<int>> res; // 存放结果集
void backtracking(int n, int k, int sum, int startIndex){
}
- 确认终止条件
当 path 里的元素个数等于 k ,并且 sum (path里元素的总和) 等于 n 时说明符合组合条件,加入最终的结果集 res 里。并且 sum 若大于 n 也没有接下去搜索的必要。
vector<int> path; // 符合条件的结果
vector<vector<int>> res; // 存放结果集
void backtracking(int n, int k, int sum, int startIndex){
if(sum > n) return; // 剪枝操作 若sum > n 也没有接下去搜索的必要
if(path.size() == k){
if(sum == n) res.push_back(path); // 符合条件的结果放入结果集
return;
}
}
- 单层搜索过程
从1 ~ 9 内每次选取一个元素 i 加入path,并且sum += i,然后进入下一次的递归函数当中,注意下一层的 startIndex为 i + 1,然后进行最关键的回溯,sum -= i , path中最后一个元素退出。
vector<int> path; // 符合条件的结果
vector<vector<int>> res; // 存放结果集
void backtracking(int n, int k, int sum, int startIndex){
if(sum > n) return; // 剪枝操作 若sum > n 也没有接下去搜索的必要
if(path.size() == k){
if(sum == n) res.push_back(path); // 符合条件的结果放入结果集
return;
}
// i <= 9 - (k - path.size()) + 1 剪枝操作
for(int i = startIndex; i <= 9 - (k - path.size()) + 1; i++){
sum += i;
path.push_back(i);
backtracking(n , k, sum, i + 1); // 注意 startIndex 调整为 i + 1
sum -= i; // 回溯
path.pop_back(); // 回溯
}
}
这样回溯算法的递归函数就写完了,最后记住在调用的时候设置sum 和 startIndex 的初始值,完整代码如下:
class Solution {
private:
vector<int> path; // 符合条件的结果
vector<vector<int>> res; // 存放结果集
void backtracking(int n, int k, int sum, int startIndex){
if(sum > n) return; // 剪枝操作 若sum > n 也没有接下去搜索的必要
if(path.size() == k){
if(sum == n) res.push_back(path); // 符合条件的结果放入结果集
return;
}
// i <= 9 - (k - path.size()) + 1 剪枝操作
for(int i = startIndex; i <= 9 - (k - path.size()) + 1; i++){
sum += i;
path.push_back(i);
backtracking(n , k, sum, i + 1); // 注意 startIndex 调整为 i + 1
sum -= i; // 回溯
path.pop_back(); // 回溯
}
}
public:
vector<vector<int>> combinationSum3(int k, int n) {
backtracking(n, k, 0, 1);
return res;
}
};
执行结果:
通过
显示详情
添加备注
执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:6.1 MB, 在所有 C++ 提交中击败了96.41%的用户
通过测试用例:18 / 18