[C++]LeetCode: 34 Combination Sum II


タイトル:
Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Each number in C may only be used once in the combination.
Note:
All numbers (including target) will be positive integers.
Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
The solution set must not contain duplicate combinations.
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]  
考え方:Combination Sumと似ていますが、この問題では重複する要素を使用できないことが要求されています.再帰するときに伝わるindexは、現在の要素の次の要素であるはずです.大まかに考えてこの点を修正すればよい,すなわち遡及の仕方を変えることができる.すべての可能性が貧しいわけではない.
Attention:
1. “if(i > index && num[i] == num[i-1]) continue;  ”
重複する要素の同じ反復を避けることが考慮される.次の繰り返し要素が一致する場合は、前の要素の反復が考慮されており、直接スキップできます.
しかし、重複する結果セットを避けるために、私たちは初めて得たこの数だけを再帰し、次にこの要素をスキップします.次の状況は前の階層の再帰関数で考慮されるので、重複要素の出現を避けることができます.
2. “if(target < 0 || index >= num.size())   return;”
次の要素が入力されるため,処理前に要素を判断する必要がある.
3. “ivec.pop_back();” この文はとても重要で、忘れてはいけません.
4.この問題では重複数を使用しないことが必要ですが、要素の重複は許可されています.したがって,ボリュームは不要でも重複数を削除することはできない.
結果セットの繰り返し:
Input:
[1,1], 1
Output:
[[1],[1]]
Expected:
[[1]]
Anwser 1:判定条件で結果セットの重複を避ける.
AC Code:
class Solution {
public:
    vector<vector<int> > combinationSum2(vector<int> &num, int target) {
        vector<vector<int>> ret;
        if(num.size() == 0) return ret;
        std::sort(num.begin(), num.end());
        vector<int> tmp;
        recurse(tmp, num, 0, target, ret);
        return ret;
    }
    
private:
    void recurse(vector<int> &ivec, vector<int> &num, int index, int target, vector<vector<int>> &ret){
        if(target == 0)
        {
            ret.push_back(ivec);
            return;
        }
        if(target < 0 || index >= num.size())
            return;
                
        if(num[index] <= target)
        {
            for(int i = index; i < num.size() && num[i] <= target; i++)
            {
                if(i > index && num[i] == num[i-1]) continue;   //                   。                          ,      。
                ivec.push_back(num[i]);
                int newtarget = target - num[i];
                recurse(ivec, num, i + 1, newtarget, ret);
                ivec.pop_back();
            }
        }
    }
};

Anwser 2:データ構造を変更し,重複を防止しsetコンテナを使用する.(もっといい!!)
AC Code:
class Solution {
public:
    vector<vector<int> > combinationSum2(vector<int> &num, int target) {
        set<vector<int>> rs;
        if(num.size() == 0) return vector<vector<int>>();
        std::sort(num.begin(), num.end());
        vector<int> tmp;
        recurse(tmp, num, 0, target, rs);
        return vector<vector<int>>(rs.begin(), rs.end());  
    }
    
private:
    void recurse(vector<int> &ivec, vector<int> &num, int index, int target, set<vector<int>> &ret){
        if(target == 0)
        {
            ret.insert(ivec);
            return;
        }
        if(target < 0 || index >= num.size())
            return;
                
        if(num[index] <= target)
        {
            for(int i = index; i < num.size() && num[i] <= target; i++)
            {
                if(i > index && num[i] == num[i-1]) continue;   //                   。                          ,      。
                ivec.push_back(num[i]);
                int newtarget = target - num[i];
                recurse(ivec, num, i + 1, newtarget, ret);
                ivec.pop_back();
            }
        }
    }
};