组合问题
组合不强调顺序,排列强调顺序
回溯法解决的问题都可以抽象为树形结构,组合的大小构成了树的宽度,递归的深度构成了树的高度
回溯三部曲
- 回溯模板的返回值以及参数
- 返回值一般为void
- 先写逻辑看需要什么参数就放什么参数
- 回溯的终止条件
- 回溯搜索的遍历过程
回溯模板:
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
77.组合
给定两个整数
n
和k
,返回范围[1, n]
中所有可能的k
个数的组合。你可以按 任何顺序 返回答案。
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
backtracking(n,k,1);
return res;
}
private void backtracking(int n,int k,int startIndex){
if(path.size()==k){
res.add(new ArrayList<>(path));
return;
}
for(int i=startIndex;i<=n-(k-path.size())+1;i++){
path.add(i);
backtracking(n,k,i+1);
path.removeLast();
}
}
}
这是回溯+剪枝的结果
随着path.size()的增加,可选择范围减少,需要的大小为k
k-path.size() : 表示剩下的大小
在集合n中至多要从该起始位置 n - (k-path.size())+1 开始遍历 {注意这是起点的位置!!!startIndex!!!表示从这开始到集合末尾还有k-path.size() 个元素,如果起点比这个位置还往后那么是无意义的因为剩余的元素不能构成K大小的path}
(为什么需要+1,因为包括起始位置,需要一个左闭的的集合)
举例:n =4 , k =3 假设size为0那么最多从 4- (3-0) +1 = 2 开始遍历是合理的 -> [2 , 3 , 4]