質問の説明
一連の候補番号 candidates
とターゲット番号 target
を指定すると、 candidates
内のすべての候補を見つけます。数値の合計は target
の組み合わせになります。
candidates
の各数値は、各組み合わせで 1 回のみ 使用できます。
注: ソリューション セットには、繰り返しの組み合わせを含めることはできません。
サンプル入力
例 1:
入力: 候補 = [10,1,2,7,6,1,5]、ターゲット = 8 出力: [ [1,1,6]、 [1,2,5]、 [1,7]、 [2,6] ]
例 2:
入力: 候補 = [2,5,2,1,2]、ターゲット = 5、 出力: [ [1,2,2]、 [5] ]
ヒント:
1 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30
答え
この質問とこの質問 の合計 (バックトラッキング) - CSDN ブログの違いは、candidates
候補セット には繰り返しの要素がありますが、解セットには繰り返しの組み合わせが含まれない必要があるため、 解セットの重複を排除する必要があります。
たとえば、以下に示すように候補 = [10,1,2,7,6,1,5]、ターゲット = 8 の場合、明らかに [1,7 ]は解セットですが、 candidates
には 2 つの要素 1、つまり図のポインタ a とポインタ c があります。要素をポイントする場合、バックトラッキング手法を使用してトラバースすると、必然的に2 つの解セット [1,7] が存在し、1 つは [a,b]、もう 1 つは [b,c] になります。 ] 。 質問の意味と矛盾します ですが、それらはすべて解決策セット [1,7] であり、
重複排除について
まず候補配列を並べ替え、次のシーケンスを取得します:
次に、 バックトラッキング メソッドを使用して、並べ替えられた候補をスキャンします。隣接する同一の要素が見つかった場合 (candidates[i-1]==candidates[i])、スキップします。 。
次の疑問は、バックトラッキング メソッドでこのプロセスをどのようにシミュレートするかということです。
問題の説明を容易にするために、候補 =[1,1,2]、ターゲット =3 と仮定します。
下の図に示すように、並べ替えられた候補が隣接する同一の要素に遭遇した場合、候補[i-1]==候補[i]が存在する必要があります。しかし、問題は、この場合、同じブランチの下の の深度トラバーサルの合計です。同じ層の水平走査が発生し、必要な重複排除は同じツリー層の重複排除です。つまり、同じ層の走査では、candidate[i-1]==candidates[i] の場合にスキップされます。 』に遭遇。
これら 2 つの状況を区別するために、used 補助配列を使用して各数値フェッチのプロセスを記録します。つまり、数値が毎回フェッチされる場合、used の対応する位置が true に設定されます。
以下の図からわかるように、candidates[i] ==candidates[i - 1] の場合も同じ状況が発生します。
used[i - 1] == true、同じブランチ上の候補[i - 1] が使用されていることを示します
used[i - 1] == false、同じブランチ上の候補[i - 1] が使用されていることを示します同じツリー レイヤー上の候補 [i - 1] 使用
したがって、要件を満たす重複排除プロセスは次のように表すことができます。
候補者[i] == 候補者[i - 1] および used[i - 1] == false の場合、前のブランチは候補者[i - 1] を使用しました。つまり、同じツリー層が候補者を使用しました。 [i-1]。
このとき、for ループ内で continue 操作を実行する必要があります。
used[i - 1] == false が同じツリー レベルを意味するのはなぜですか? used[i - 1] == false だけが同じツリー レベルを表すことができるからです。現在フェッチされている候補者[i] は候補者[i - 1] からバックトラックされます。 。 来る。 used[i - 1] == true は、再帰の次のレベルに入り、次の番号に進むことを示し、分岐上にあります。
代码
class Solution {
private:
vector<int> path;
vector<vector<int>> res;
public:
void backing(vector<int>& candidates,int target,int startIndex,int curSum,vector<bool>& used)
{
if(curSum>target) return;
if(curSum==target)
{
res.push_back(path);
return;
}
for(int i=startIndex;i<candidates.size() && curSum+candidates[i]<=target;i++)
{
if(i>0 && candidates[i-1]==candidates[i] && used[i-1]==false)
{
continue;
}
else
{
curSum+=candidates[i];
used[i]=true;
path.push_back(candidates[i]);
backing(candidates,target,i+1,curSum,used);
path.pop_back();
curSum-=candidates[i];
used[i]=false;
}
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
vector<bool> used(candidates.size(),0);
backing(candidates,target,0,0,used);
return res;
}
};