候補の配列とターゲット数のターゲットが与えられた場合、数の合計をターゲットにすることができる候補のすべての組み合わせを見つけます。
候補者の各番号は、各組み合わせで1回のみ使用できます。
説明:
すべての数値(ターゲット数値を含む)は正の整数です。
ソリューションセットに繰り返しの組み合わせを含めることはできません。
例1:
入力:候補= [10,1,2,7,6,1,5]、目標= 8、
ソリューションセットである:
[
[1,7]、
[1、2、5]、
[2]、[6]、
[1、1、6]
]
分析:
他の組み合わせと比較すると、この質問の違いは、元の配列に繰り返し要素が含まれていることと、ソリューションセットに繰り返し組み合わせがないことです。重要なのは、ツリーのルートを重複排除することです。たとえば、3つの要素すべてa {1,1,2}のをルートとして使用できますが、a [0]、a [1]とa [1]、a [0]は重複しているため、「ルート」としてa [1]を選択すると、要素を「ルート」として使用できるかどうかを判断する必要があります。ここでは、各要素の使用状況を記録するために、使用される配列を紹介します。
「ルート」として使用される可能性のある新しい要素に移動するときは、最初に前の要素が同じであるかどうかを確認します。同じである場合は、使用されている配列若used[i - 1] == false 说明这两个节点在数结构的一层,都是等着被选做“根”的,是横着走过来的,如果used[i - 1] == true,则说明是一条树枝,是从上到下走过来的。
を確認します。重複を削除するには、次のようにします。これらの繰り返される要素の1つだけを作成します。ブランチは、繰り返される要素がツリーのルートになることを許可しないため、falseに遭遇した場合はスキップし、trueに遭遇した場合は一意のブランチを形成します(組み合わせ)
class Solution {
public:
vector<vector<int>> ret;
vector<int> path;
void backTracking(vector<int>& candidates, int target, int startIndex, vector<bool>& used){
if(target == 0){
ret.push_back(path);
return;
}
if(target < 0){
return;
}
for(int i = startIndex; i < candidates.size(); i++){
// 去重的关键语句:
// used[i - 1] == false 说明这两个节点在数结构的一层,都是等着被选做“根”的
// 如果used[i - 1] == true,则说明是一条树枝,从上到下走过的
// 我们要做到的去重就是让这些重复的元素只做出来一条树枝,不让重复的元素再次当树根
// 所以遇到false就跳过,遇到true就让它们组成一条唯一的树枝(组合)
if(i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false){
continue;
}
used[i] = true;
target -= candidates[i];
path.push_back(candidates[i]);
backTracking(candidates, target, i + 1, used);
used[i] = false;
target += candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
// 初始化used数组
vector<bool> used(candidates.size(), false);
sort(candidates.begin(), candidates.end());
backTracking(candidates, target, 0, used);
return ret;
}
};