LeetCodeの組み合わせの合計Ⅱ
@author:Jingdai
@date:2020.11.30
トピックの説明(40の質問)
配列
candidates
とターゲット番号が与えられtarget
たら、candidates
すべての番号を見つけて、そのtarget
組み合わせを作ることができます。
candidates
の各番号は、各組み合わせで1回のみ使用できます。説明:
- すべての数値(ターゲット数値を含む)は正の整数です。
- ソリューションセットに繰り返しの組み合わせを含めることはできません。
例:
输入: candidates = [2,5,2,1,2], target = 5 输出: [ [1,2,2], [5] ]
アイデアとコード
この質問を最初に見たとき、処理方法を考えました。番号ごとに、選択する方法と選択しない方法の2つの方法があります(01バックパックに少し似ています)。現在の番号を処理した後、結果が見つかるか、各番号が処理されるまで、次の番号でdfsを実行します。同時に、最初にcandidates
配列全体を並べ替えることができ、現在のノードが、より大きい場合は並べ替えるtarget
ことができます。また、整理することができ、dfsの後に下がる必要はありません。写真は千の言葉の価値があります、写真を見てください。
次に、このアイデアに基づいて次のコードを記述します。
public List<List<Integer>> combination = new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
LinkedList<Integer> tempCombination = new LinkedList<>();
Arrays.sort(candidates);
dfs(candidates, target, 0, tempCombination);
return combination;
}
public void dfs(int[] candidates, int target, int index, LinkedList<Integer> tempCombination) {
if (target == 0) {
combination.add(new LinkedList<Integer>(tempCombination));
return;
}
if (index == candidates.length) {
return;
}
if (candidates[index] > target) {
return;
}
// target >= candidate[i]
// choose index
tempCombination.add(candidates[index]);
target -= candidates[index];
dfs(candidates, target, index+1, tempCombination);
target += candidates[index];
tempCombination.removeLast();
// dont choose index
dfs(candidates, target, index+1, tempCombination);
}
完璧に見えますが、タイトルは繰り返しの解決策を必要とせず、私たちの方法を繰り返すことができないため、提出されたときはばかげていて、それをやり遂げることができませんでした。重複を削除するにはどうすればよいですか?結果セットの重複を排除することを選択できますが、これはより面倒なので、考えを変えてください。
各数値の選択と非選択に対してdfsを実行しました。解空間ツリーの各層は、数値の選択と非選択です。これは重複を取り除くのは簡単ではありません。図に示すように角度を変更し、毎回異なる数を選択して、各レイヤーの数が確実に異なるようにすることができます。また、下位層は上位層と同じ番号を選択できます(それ以上の場合)。ソリューションスペースツリーの各レイヤーは、これまで選択されたことのないさまざまなノードの選択です。
次回の開始インデックスは、現在のインデックスの次のインデックスであることに注意してください。前のインデックスを選択し続けると、前のインデックスと確実に同じになるためです。たとえば、最初に2を選択してから1を選択した場合、ブランチは1を選択してから2を選択したブランチと同じになります。このようにして、重複するソリューションを簡単に削除できます。剪定の考え方は以前と同じなので、繰り返しません。コードは以下のように表示されます。
public List<List<Integer>> combination = new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
LinkedList<Integer> tempCombination = new LinkedList<>();
Arrays.sort(candidates);
dfs(candidates, target, 0, tempCombination);
return combination;
}
public void dfs(int[] candidates, int target, int begin, LinkedList<Integer> tempCombination) {
if (target == 0) {
combination.add(new LinkedList<>(tempCombination));
return;
}
for (int i = begin; i < candidates.length; i++) {
if (i > begin && candidates[i] == candidates[i-1]) {
continue;
}
if (candidates[i] > target) {
return;
}
// choose
target -= candidates[i]; // target >= candidates[i]
tempCombination.add(candidates[i]);
dfs(candidates, target, i+1, tempCombination);
// backtrack
target += candidates[i];
tempCombination.removeLast();
}
}