力扣打卡:77. 组合
解题思路
- 需要求解所有的可能, 并且没有子问题重复的题目,那么一定是暴力求解,可以考虑回溯
回溯的框架
// 常用的结果储存
List<T> track = new LinkedList<>();
List<List<T>> res = new LinkedList<>();
public void backtrack(){ // 先将需要的参数确定下来,然后一边写流程一边考虑是否加参数
if(终止条件){
存放结果集,return ;
}
for(所有的可能){ // 三步骤 做选择, 去递归, 撤销选择 -- > 做选择 去尝试 再反悔
1. 做选择
2. backtrack()
3. 撤销选择
}
}
思路
- 根据题目的要求可以知道, 有k个数字在组合, 那么也就是说明了终止条件, 存放可能的
track
的size
只要等于k
,那么久开始存放结果 - 因为任意一个元素不是使用任意次,而是只是使用一次
for
的遍历所有可能, 应该变为这个元素后的所有元素
或者这个元素前的所有元素
- 遍历所有的可能的同时, 每次都需要做三个步骤
- 做选择 (做选择)
- 去递归 (去尝试)
- 撤销选择 (再反悔)
代码
class Solution {
List<Integer> track = new LinkedList<>();
List<List<Integer>> res = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
// 所有可能的集合,没有重叠的子问题,暴力求解,也就是回溯
backtrack(1, n, k);
return res;
}
public void backtrack(int p, int n, int k){
if(track.size()==k){// 根据题目给定的内容和条件,写出终止条件
res.add(new LinkedList<>(track));
return ;
}
// 暴力穷举出所有的可能
for(int i=p; i<=n; i++){
track.add(i); // 做选择
backtrack(i+1, n, k); // 继续递归
track.remove(track.size()-1); // 递归之后撤销选择
}
}
}