代码随想录算法训练营 day 24: 77. 组合

83 阅读1分钟

77. Combinations

 

Example 1:

Input: n = 4, k = 2
Output: [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
Explanation: There are 4 choose 2 = 6 total combinations.
Note that combinations are unordered, i.e., [1,2] and [2,1] are considered to be the same combination.

Example 2:

Input: n = 1, k = 1
Output: [[1]]
Explanation: There is 1 choose 1 = 1 total combination.

 

Constraints:

  • 1 <= n <= 20
  • 1 <= k <= n

Carl 提供的回溯模板很有用,以前递归也能写但没做过这样的总结。 模板

void backtracking(参数) { if (终止条件) { 存放结果; return; }

for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
    处理节点;
    backtracking(路径,选择列表); // 递归
    回溯,撤销处理结果
}

}

组合是标准递归问题,每层递归处理一个长度的组合,用for循环call遍余下的元素。递归由上到下,按数组顺序来选元素。用一个startIndex来标记本层的起始元素位置。 选满k个元素,就把当前选过的元素集合加到结果集里。 剪枝操作,就是在当前循环中,如果剩下的元素不足以填满k,就没必要继续遍历。

class Solution {
    public void backtracking(List<Integer> path, int n, int k, int start, List<List<Integer>> res) {
        if(path.size() == k) {
            res.add(new ArrayList<>(path));
            //System.out.println(path.toString());
            return;
        }

        for(int i=start; i<=n - (k-path.size()) + 1; i++) {
            path.add(i);
            backtracking(path, n, k, i+1, res);
            path.remove(path.size() - 1);
        }


    }
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        List<Integer> path = new ArrayList<Integer>();

        backtracking(path, n, k, 1, res);

        return res;
    }
}