题目描述
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
- 所有数字(包括 target)都是正整数。
- 解集不能包含重复的组合。
示例 1:
- 输入:candidates = [2,3,6,7], target = 7,
- 所求解集为: [ [7], [2,2,3] ]
示例 2:
- 输入:candidates = [2,3,5], target = 8,
- 所求解集为: [ [2,2,2,2], [2,3,3], [3,5] ]
解题思路
本题搜索的过程抽象成树形结构如下:
注意图中叶子节点的返回条件,因为本题没有组合数量要求,仅仅是总和的限制,所以递归没有层数的限制,只要选取的元素总和超过target,就返回!
回溯三部曲
-
递归函数的参数
定义两个全局变量,二维数组result存放结果集,数组path存放符合条件的结果。首先是题目中给出的参数,集合candidates, 和目标值target。
此外还需要定义int型的sum变量来统计单一结果path里的总和,startIndex来控制for循环的起始位置。
vector<vector<int>> result; vector<int> path; void backtracking(vector<int>& candidates, int target, int sum, int startIndex)
-
递归函数的终止条件
终止只有两种情况,sum大于target
和sum等于target
。sum等于target的时候,需要收集结果,代码如下:
if (sum > target) { return; } if (sum == target) { result.push_back(path); return; }
-
单层搜索的逻辑
单层for循环依然是从startIndex开始,搜索candidates集合。for (int i = startIndex; i < candidates.size(); i++) { sum += candidates[i]; path.push_back(candidates[i]); // 关键点:不用i+1了,表示可以重复读取当前的数 backtracking(candidates, target, sum, i); sum -= candidates[i]; // 回溯 path.pop_back(); // 回溯 }
代码实现
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {
if (sum > target) {
return;
}
if (sum == target) {
result.push_back(path);
return;
}
for (int i = startIndex; i < candidates.size(); i++) {
sum += candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, sum, i); // 不用i+1了,表示可以重复读取当前的数
sum -= candidates[i];
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
result.clear();
path.clear();
backtracking(candidates, target, 0, 0);
return result;
}
};