39. 组合总和
给定一个无重复元素的数组 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]
]
分析:
首先我们可以暴力枚举出所有的正确组合。但是会存在"重复"问题。如[2,2,3], [3,2,2],[2,3,2]…
如何去重呢?
对于重复的问题,是因为在某一解中我们已经先添加了candidates[i] , 然后再加入candidates[j] (i < j) ; 而在另一个解中是按照:先添加candidates[j] 后 加入 candidates[i] 所造成的。
所以为了防止重复解出现,我们只需规定: 在某一个可行解中,它的所有元素是按照它们在candidates[]中的索引大小顺序添加的,即:不能先添加后面的数,再添加前面的数。
我们使用 int used 来表示:当前组合cur[]中,已经使用到了第used个元素,所以之后为了不产生重复解,cur[]只能从candidates[used]开始添加。
dfs函数参数的含义:
cur : 当前试探的组合
sum: 当前组合的和
used: 当前组合cur[]中,已经使用到了第used个元素
…
优化:剪枝
先将candidates[]排序,若添加某个数后sum > target ,由于后面的数更大,一定也会使得 sum > target, 所以不用考虑,可以直接剪枝掉。
AC代码:
class Solution {
public:
int n;
void dfs(vector<int> cur, int sum, int used, vector<vector<int>>& ans,vector<int>& candidates,int target)
{
if(sum > target) return;
if(sum == target)
{
ans.push_back(cur);
return;
}
for(int i=used;i<n;i++)
{
vector<int> t = cur;
t.push_back(candidates[i]);
dfs(t,sum+candidates[i],i,ans,candidates,target);
if(sum+candidates[i] > target) break;
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
vector<vector<int>> ans;
vector<int> cur;
n = candidates.size();
dfs(cur,0,0,ans,candidates,target);
return ans;
}
};