题目:
Given a collection of candidate numbers (candidates
) and a target number (target
), find all unique combinations in candidates
where the candidate numbers sum to target
.
Each number in candidates
may only be used once in the combination.
Note: The solution set must not contain duplicate combinations.
Example 1:
Input: candidates = [10,1,2,7,6,1,5], target = 8 Output: [ [1,1,6], [1,2,5], [1,7], [2,6] ]
Example 2:
Input: candidates = [2,5,2,1,2], target = 5 Output: [ [1,2,2], [5] ]
Constraints:
1 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30
思路:
这题是39. Combination Sum的follow up,真正想清楚还是有难度的。难点在于可以选择重复数字,但是不能有重复组合,举个例子,例1中[10,1,2,7,6,1,5],会出现[1, 7]和[7, 1],这就是同一个组合,是不允许的;但是如果选择[1, 6, 1],两个1都选了,这就可以。我们可以发现,如果是在同一趟选择中,选两个相同的数字是可以,否则就不能选两个相同的数字。这里就有个很重要的点,先进行排序,这样例1就是[1, 1, 2, 5, 6, 7, 10],那么如果选择了第一个1,再选第二个1就是可以的;如果第一次选了第一个1,然后backtracking的时候,把这个1pop掉了,又选了第二个1,这就是一种重复组合的行为,想明白这点对于这题十分重要。我们通过visited来记录,如果用过candidates[i]这个数,visited[i]就设为true。那么当visited[i - 1] == visited[i]且visited[i -1]为false时,就是我们说的重复组合情况了,前一个相同的数字我们没选,那么当前这个就没必须要选了,因为会和选择前一个数字变成同种组合,直接continue即可。剩下就是backtracking之后,除了pop_back,也要记得将visited[i]的true重置成false。
代码:
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int> candidates, int target) {
sort(begin(candidates), end(candidates));
visited = vector<bool>(candidates.size(), false);
backtracking(candidates, target, 0);
return res;
}
private:
vector<vector<int>> res;
vector<int> path;
vector<bool> visited;
void backtracking(vector<int>& candidates, int target, int cur) {
if (target == 0) {
res.push_back(path);
return;
}
for (int i = cur; i < candidates.size(); i++) {
if (i > 0 && candidates[i] == candidates[i - 1] && visited[i - 1] == false)
continue;
if (target - candidates[i] >= 0) {
path.push_back(candidates[i]);
visited[i] = true;
backtracking(candidates, target - candidates[i], i + 1);
visited[i] = false;
path.pop_back();
}
}
}
};