LeetCode刷题day24|77 组合

文章目录

组合

题目做出来了,但踩了很多坑,且没有使用到剪枝操作。
这里,先介绍一下回溯算法的通用模板:

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

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

在组合问题中,主要需要主要的点:

  1. 在每个节点集合寻找子解的过程中,需要每次从i+1的位置开始遍历,这样会使组合总是从小到大排列,避免重复。
  2. 在递归函数中,注意使用 +1 而不是 ++,如果要++,则一定要记住在回溯中–。
  3. 剪枝操作,这里剪枝的思想是:当前数组中剩余可以取的数要比解还需要的数量少时,就不可能成为解了,此时不再继续遍历。

以下是代码部分:

public class 组合77 {

    public List<List<Integer>> combine(int n, int k) {

        List<List<Integer>> res = new ArrayList<>();
        List<Integer> list = new ArrayList<>();

        backtrcking(res, list, n, k, 0);

        return res;

    }

    private void backtrcking(List<List<Integer>> res, List<Integer> list, int n, int k, int start){

        //如果到了叶子节点
        if(k == 0){

            List<Integer> l = new ArrayList<>(list);
            res.add(l);
            //忘记return,虽然对答案没有影响
            return;
        }

        //额外定义一个start,让组合的数组总是从小到大排,避免重复。组合的数组始终是升序数组
        //for(int i = start; i<n; i++){
        //剪枝操作: n - k + 1
        for(int i = start; i<n-k+1; i++){

            //处理节点
            //踩坑:1-n 不是0-n-1
            list.add(i+1);
            //递归、回溯
            backtrcking(res, list, n, k-1, i+1);        //踩坑:1这里是i++,而不是start++         2刚开始用的k--,i++
            list.remove(list.size()-1);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值