题目
给定一个候选人编号的集合 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates =[10,1,2,7,6,1,5]
, target =8
, 输出: [ [1,1,6], [1,2,5], [1,7], [2,6] ]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5, 输出: [ [1,2,2], [5] ]
提示:
1 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30
思路
因为有可能出现重复组合或者数组中的数本身都比目标值要大,所以我们就要规避这种现象,我们可以先对数组中的数进行排序,如果有数字大于目标值那么这个数一定不能在组合里面,这个数字后面的数也一定不能,就可以省去一些搜索步骤。在遍历中,从start开始可以避免重复,如果前一个数和自己相等就跳过,防止产生重复组合,经过筛选,符合条件的数就先存在临时数组p中,如果从下一轮回溯又返回到当前,那么就把这个数弹出,用其他数继续试。
代码
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<int> p;//存组合中的数字
sort(candidates.begin(), candidates.end());//排序,方便判断数字是否能作为组合中符合条件的数字
int start=0;//从0开始遍历
vector<vector<int>> res;//结果数组
hs(p, target, candidates, start, res);
return res;
}
void hs(vector<int>& p,int target,vector<int> &c,int start,vector<vector<int>> &res)
{
if(target==0)//代表找到了符合条件的组合
{
res.push_back(p);
return;
}
for(int i=start;i<c.size();i++)//避免生成重复组合
{
if(target-c[i]<0)//因为数组是经过排序的,当前数字比目标值还要大,剩下的也都不用在判断了
{
break;
}
if(i>start&&c[i]==c[i-1])//前一个数和当前数相等,会导致重复,跳过
{
continue;
}
p.push_back(c[i]);//数字符合条件,先存入
hs(p,target-c[i],c,i+1,res);//下一轮
p.pop_back();//回溯,恢复之前状态,生成更多选择
}
}
};