代码随想录第二十四天

内容:

  1. 组合(77)

1. 组合

难度:🔥🔥🔥

建议:对着在回溯算法理论基础给出的代码模板,来做本题组合问题,大家就会发现 写回溯算法讨论。

在回溯算法解决实际问题的过程中,大家会有各种疑问,先看视频介绍,基本可以解决大家的疑惑。

本题关于剪枝操作是大家要理解的重点,因为后面很多回溯算法解决的题目,都是这个剪枝套路。

1.1 思路分析

这道题目是回溯算法组合问题的经典题目。

我们一般将组合问题抽象成为如下树形结构,如图:

77.组合

而树的宽度与树的深度分别对应题目中的n,k图中每次搜索到了叶子节点,我们就找到了一个结果。

我们接下来使用回溯三部曲即可解决这道题目。

1.2 代码实现
class Solution {
    //使用LinkedList
    LinkedList<Integer> path = new LinkedList<>();
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> combine(int n, int k) {
        backtracking(n,k,1);
        return result;
    }

    /**
     *
     * @param n [1,n] 之间的数
     * @param k 一共k个数
     * @param startIndex 开始的索引数
     */
    private void backtracking(int n,int k,int startIndex){
        if(path.size() == k){
            //这里不可以直接使用path
            result.add(new ArrayList<>(path));
            return;
        }
        //剪枝操作 n -> n - (k - path.size()) + 1
        for(int i = startIndex;i <= n - (k - path.size()) + 1;i++){
            path.add(i);
            backtracking(n,k,i + 1);
            path.removeLast();
        }

    }
}
1.3 注意事项
  • 在问题中我们可以对回溯算法进行一些剪枝操作

如图:

77.组合4

所以在for(int i = startIndex;i <= n;i++)中我们可以优化为

for(int i = startIndex;i <= n - (k - path.size()) + 1;i++)

优化过程如下:

  1. 已经选择的元素个数:path.size();
  2. 所需要的元素个数为: k - path.size();
  3. 列表中剩余元素(n-i) >= 所需要的元素个数(k - path.size())
  4. 在集合n中至多要从该起始位置 : i <= n - (k - path.size()) + 1,开始遍历

为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。

举个例子,n = 4,k = 3, 目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 4 - ( 3 - 0) + 1 = 2,所以最大从2开始搜索,从3开始则不行。

  • result集合中添加中间路径path时不能直接加入path,因为path实际上是地址,而无论加入多少个path都是同一个对象。并且在回溯后都会清空,最后得到的集合都为空。所以需要我们去new一个ArrayList()
1.4 收获总结

回溯算法模板–来自代码随想录

//for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历
void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值