题目描述
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:
- 所有数字都是正整数。
- 解集不能包含重复的组合。
示例 1: 输入: k = 3, n = 7 输出: [[1,2,4]]
示例 2: 输入: k = 3, n = 9 输出: [[1,2,6], [1,3,5], [2,3,4]]
解题思路
本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为 n 的 k 个数的组合。
本题k相当于树的深度,9(因为整个集合就是9个数)就是树的宽度。
回溯三部曲
-
确定递归函数的参数
这里需要一个一维数组path来存放符合条件的结果,一个二维数组result来存放结果集。vector<vector<int>> result; vector<int> path;
还需要如下参数:
- targetSum(int),目标和,也就是题目中的n
- k(int),题目中要求的 k 个数的集合
- sum(int),已经收集的元素的总和,也就是path里元素的总和
- startIndex(int),下一层for循环搜索的起始位置
void backtracking(int targetSum, int k, int sum, int startIndex)
-
确定终止条件
如果path.size() == k
就可以终止了。如果此时path里收集到的元素和(sum) 和targetSum(就是题目描述的n)相同了,就用result收集当前的结果。if (path.size() == k) { if (sum == targetSum) result.push_back(path); return; }
-
单层搜索的过程
集合固定的就是9个数[1,…,9],所以for循环固定i<=9处理过程就是 path收集每次选取的元素,相当于树型结构里的边,sum来统计path里元素的总和。
for (int i = startIndex; i <= 9; i++) { sum += i; path.push_back(i); backtracking(targetSum, k, sum, i + 1); sum -= i; path.pop_back(); }
-
剪枝操作
已选元素总和如果已经大于n了,那么往后遍历就没有意义了,直接剪掉。if (sum > targetSum) return;
代码实现
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(int targetSum, int k, int sum, int startIndex) {
if (sum > targetSum) {
return;
}
if (path.size() == k) {
if (sum == targetSum) result.push_back(path);
return;
}
for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) {
sum += i;
path.push_back(i);
backtracking(targetSum, k, sum, i + 1);
sum -= i;
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum3(int k, int n) {
result.clear();
path.clear();
backtracking(n, k, 0, 1);
return result;
}
};