【Кнопка Li】77. Комбинация
Учитывая два целых числа n и k, верните все возможные комбинации k чисел в диапазоне [1, n]. Вы можете возвращать ответы в любом порядке.
Пример 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 эквивалентно глубине дерева. Каждый раз, когда в графе выполняется поиск листового узла, результат находится.
Три шага возврата
-
Возвращаемое значение и параметры рекурсивной функции
-
Условие завершения функции возврата
-
Процесс одноуровневого поиска
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();
}
}
}