原题地址(中等)

方法1—回溯

这题和第39题组合总和极其相似,实际上会了那道题,这道题就自然而然了。
附上39题题解。
39. 组合总和
这题有稍稍的变动,就是元素不能重复使用了, 但是数组中可以含有重复的元素

可以在39题最基本的回溯解法上加上哈希表来去重,此解法不再赘述。
第二个就是继续沿用威威哥的解法。
贴出39题代码中的回溯函数。

  1. void dfs(vector<int> candidates, int k, int cur, int end){
  2. if(k < 0) return;
  3. if(k == 0){
  4. vv.push_back(v);
  5. return ;
  6. }
  7. // 回溯
  8. for(int i=cur; i<=end; i++){
  9. v.push_back(candidates[i]);
  10. dfs(candidates, k-candidates[i], i, end);
  11. v.pop_back();
  12. }
  13. }

因为39题是可以重复利用当前元素,所以循环中会出现 dfs(candidates, k-candidates[i], i, end); ,如果不能重复利用元素,那么代码应该改为 dfs(candidates, k-candidates[i], ``i+1``, end);

但是这样仍然不能避免重复,因为有可能会出现 candidates=[1,1,1,1,1,2] 这种同一元素多次出现的情况。这样我们怎么处理呢?
答案就是只处理第一个 1 ,剩下的 1 直接忽略掉,也就是

  1. if(i > cur && candidates[i] == candidates[i-1])
  2. continue;

最终代码

  1. class Solution {
  2. public:
  3. set<vector<int>> ans;
  4. vector<int> v;
  5. void dfs(vector<int> candidates, int cur, int end, int target){
  6. if(target==0){
  7. ans.insert(v);
  8. return;
  9. }
  10. if(cur > end || candidates[cur] > target) return;
  11. for(int i=cur; i<=end; i++ ){
  12. if(i > cur && candidates[i] == candidates[i-1])
  13. continue;
  14. v.push_back(candidates[i]);
  15. dfs(candidates, i+1, end, target-candidates[i]);
  16. v.pop_back();
  17. }
  18. }
  19. vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
  20. sort(candidates.begin(), candidates.end());
  21. int n = candidates.size();
  22. if(n==0) return {};
  23. dfs(candidates, 0, n-1, target);
  24. vector<vector<int>> vv(ans.begin(), ans.end());
  25. return vv;
  26. }
  27. };