【Liボタン】77. 組み合わせ
2 つの整数 n と k を指定すると、範囲 [1, n] 内の k 個の数値の可能なすべての組み合わせを返します。回答は任意の順序で返すことができます。
例 1:
入力: n = 4、k = 2
出力:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
例 2:
入力: n = 1、k = 1
出力:
[[1]]
ヒント:
1 <= n <= 20
1 <= k <= n
答え
暴力的な思考: k がどれだけのサイクルの層に等しいか。
//示例中k为2
int n = 4;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
sout(i+" "+j);
}
}
//示例中k为3
int n = 100;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
for (int u = j + 1; u <= n; n++) {
sout(i+" "+j+" "+u);
}
}
}
バックトラック
バックトラッキング法によって解決される問題は、木構造 (N 分木) に抽象化できます。
n はツリーの幅に相当し、k はツリーの深さに相当します。グラフ内でリーフ ノードが検索されるたびに、結果が見つかります。
後戻りの 3 つのステップ
-
再帰関数の戻り値とパラメータ
-
バックトラッキング機能の終了条件
-
単層検索のプロセス
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
import java.util.*;
public class Solution {
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
backtracking(n, k, 1);
return result;
}
public void backtracking(int n, int k, int startIndex) {
// 终止条件
if (path.size() == k) {
//存放结果
result.add(new ArrayList<>(path));
return;
}
//横向遍历
for (int i = startIndex; i <= n; i++) {
//处理节点
path.add(i);
//纵向搜索
backtracking(n, k, i + 1);
//回溯,撤销处理结果
path.removeLast();
}
}
}
枝刈りの最適化
枝刈りの場所は、再帰内の各層の for ループによって選択された開始位置です。for ループで選択された開始位置以降の要素の数が必要な要素数より少ない場合は、検索する必要はありません。
- 選択された要素の数:
path.size()
; - 引き続き必要な要素の数は次のとおりです
k - path.size()
。 - 開始位置から最大でも n 番目のセット内で、
n - (k - path.size()) + 1
トラバースを開始します。
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置
import java.util.*;
public class Solution {
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
backtracking(n, k, 1);
return result;
}
public void backtracking(int n , int k, int startIndex) {
// 终止条件
if (path.size() == k) {
//存放结果
result.add(new ArrayList<>(path));
return;
}
//横向遍历
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) {
// i为本次搜索的起始位置
//处理节点
path.add(i);
//纵向搜索
backtracking(n, k, i + 1);
//回溯,撤销处理结果
path.removeLast();
}
}
}