回溯之Leetcode 40——Combination Sum II

本题和39Combination Sum 极为相似,建议做这个题之前先把Combination Sum 做了。以下讲解是在做过Combination—Sum的基础上。 

II的题目要求不变,唯一变化了的是允许已知序列中有重复的元素和序列中的一个元素只能用一次。

依然用回溯法,递归中嵌套循环。很容想到将I中代码中的递归语句:

 dfs(ans,candidates,a,tag-candidates[i],i);

改成:

 dfs(ans,candidates,a,tag-candidates[i],i+1);

这就可以保证已知序列每一个元素只用一次。但是不要忘了题目中还说序列中允许有重复的元素。

For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8
A solution set is: 

[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

上例就是有已知序列中有重复的元素1,所以答案中有(1,1,6),但是这样会带来一个问题,会产生两个(1,2,5)(原因我就不说了),为此我决定先用一个set存储答案(简单粗暴=-=),之后在copy到一个vector里。

PS:用到的STL知识:

set容器的添加元素insert();添加元素会自动排序;

将set的元素拷贝到vector中:

insert_iterator<vector<int>> in_it(v, v.begin());
copy(s.begin(), s.end(), in_it);

详见AC代码:

class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<vector<int>> ans;
        set<vector<int>> ans_copy;
        vector<int> a;
        sort(candidates.begin(),candidates.end());
        dfs(ans_copy,candidates,a,target,0);
        insert_iterator<vector<vector<int>>> in_it(ans, ans.begin());
        copy(ans_copy.begin(), ans_copy.end(), in_it);
        return ans;
    }
    void dfs(set<vector<int>> &ans,vector<int> &candidates,vector<int> &a,int tag,int index)
    {
        if(tag==0){
            ans.insert(a);
            return;
        }
        for(int i=index;i<candidates.size();i++){
            if(candidates[i]>tag){return;}
            else{
                a.push_back(candidates[i]);
                dfs(ans,candidates,a,tag-candidates[i],i+1);
                a.pop_back();
            }
        }
        return;
    }
};

点赞