算法刷题|77.组合问题

理解回溯

回溯常常伴随着递归,回溯操作都是在递归函数的下面进行操作的。所有的回溯问题都可以抽象成一个多叉树来解决。我们之前在对二叉树进行递归遍历的时候,其实就有回溯过程,只是我们没有处理(因为不需要),但是例如找二叉树的路径的题目就涉及到回溯了。

解决回溯问题的思路:
第一步:抽象成多叉树
第二步:确定多叉树的宽度和深度
第三步:确定递归函数的终止条件
第四步:递归函数单层递归逻辑,包含回溯操作

组合问题

题目:给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。

  • 抽象成多叉树
    组合
  • 宽度就是n,体现在递归函数中的循环
  • 深度是k,体现在终止条件
class Solution {
    public List<List<Integer>> combine(int n, int k) {
        List<Integer> path = new ArrayList<>();
        List<List<Integer>> res = new ArrayList<>();
        backtracking(n,k,1,path,res);
        return res;
    }

    // startIndex:递归中开始位置
    private void backtracking(int n,int k,int startIndex,List<Integer> path,List<List<Integer>> res){
        if(path.size() == k){// 终止条件,当我们需要的组合的集合大小等于k的时候就可以收集结果了
            res.add(new ArrayList<>(path));// 这里不能直接add(path),拷贝一份path放进去,如果直接放进去那么res中的所有元素都是path对象
            return;
        }
        for(int i = startIndex;i<=n;i++){
            path.add(i);
            backtracking(n,k,i+1,path,res);
            path.remove(path.size() - 1);// 回溯
        }
    }
}

剪枝:主要就是缩小for循环的范围,例如n = 7,k = 3;那么如果循环中的i>5,后面就怎么也收集不到3个,所有5就是for循环的搜索的截止下标(包括5)

怎么计算这个截止值呢?

首先我们可以带入数据计算,例如当前一个都没有收集,n至少需要剩余3个元素才能满足条件。那么截止下标=n-k+1,为什么要+1呢,因为我们for循环是从1开始的不是从0开始的。如果我们收集了部分元素,就用k-x,就行了;就是n-(k-x)+1

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

    // startIndex:递归中开始位置
    private void backtracking(int n,int k,int startIndex,List<Integer> path,List<List<Integer>> res){
        if(path.size() == k){// 终止条件,当我们需要的组合的集合大小等于k的时候就可以收集结果了
            res.add(new ArrayList<>(path));// 这里不能直接add(path),拷贝一份path放进去,如果直接放进去那么res中的所有元素都是path对象
            return;
        }
        // 当前递归最多遍历到lastIndex
        // 例如path大小为0,lastIndex=3;如果循环中的i大于了3,后面只有一个4了,加上3才满足k=2,如果i在往后走的话,后面就可能满足k=2了
        int lastIndex = n - (k - path.size()) + 1;
        for(int i = startIndex;i<=lastIndex;i++){
            path.add(i);
            backtracking(n,k,i+1,path,res);
            path.remove(path.size() - 1);// 回溯
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值