[Ликоу] 77. Комбинация <возврат, обрезка возврата>

【Кнопка 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();
        }
    }
}

Supongo que te gusta

Origin blog.csdn.net/qq_44033208/article/details/132403081
Recomendado
Clasificación