决战圣地玛丽乔亚重新归来之Day56--算法两道

发布时间 2023-06-27 01:41:08作者: EmiXXXt

回溯算法。

组合:

给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。

示例: 输入: n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]

 

思路:如果用暴力解法,k=2,两层for循环就可以搞定,那么k=50要多少层for循环,是不合理的。

所以可以用递归的思路来完成,k的次数为递归的次数,在每次递归里进行循环。

 回溯的三个步骤:

  • 递归函数的返回值以及参数
  • 回溯函数的终止条件
  • 回溯函数的单层搜索过程

1.参数和返回值。  参数为n,k,startIndex(每次遍历的起始位置,防止重复)  由于是不可取重复次数,所以每个数只能取一次,第一次取1,下次取2,3,4

2.回溯的终止条件。   集合大小等于k

3.单层搜索过程:

for (int i = startIndex; i <= n; i++) { // 控制树的横向遍历
    path.push_back(i); // 处理节点
    backtracking(n, k, i + 1); // 递归:控制树的纵向遍历,注意下一层搜索要从i+1开始
    path.pop_back(); // 回溯,撤销处理的节点
}

最终代码:
import java.util.ArrayList;
import java.util.List;

public class Combinations {
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> results = new ArrayList<>();
        backtrack(new ArrayList<>(), 1, n, k, results);
        return results;
    }

    private void backtrack(List<Integer> combination, int start, int n, int k, List<List<Integer>> results) {
        if (combination.size() == k) {
            results.add(new ArrayList<>(combination));
            return;
        }

        for (int i = start; i <= n; i++) {
            combination.add(i);
            backtrack(combination, i + 1, n, k, results);
            combination.remove(combination.size() - 1);
        }
    }

    public static void main(String[] args) {
        int n = 4;
        int k = 2;

        Combinations combinations = new Combinations();
        List<List<Integer>> result = combinations.combine(n, k);

        for (List<Integer> combination : result) {
            System.out.println(combination);
        }
    }
}