代码随想录算法训练营第二十四天(回溯算法篇)|理论基础,77. 组合

结束了二叉树的篇章,我们进入到回溯啦!

学习资料:代码随想录 (programmercarl.com)

理论基础

回溯算法又称回溯搜算算法,是一种搜索方法。

作为递归的“副产品”,只要右递归的地方就会有对应的回溯的过程。

回溯算法为纯暴力搜索,不高效,却对解决某些问题很重要。

可以解决的问题:

理解回溯

将回溯法抽象为树形结构,回溯的问题集中在递归查找子集,集合的大小构成了树的宽度,递归的深度构成了树的深度。

回溯算法的Python模板框架如下:

def backtracking(参数):
    if(终止条件):
        存放结果;
        return
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) :
    处理节点
    backtracking(路径,选择列表)
    回溯,撤销处理结果

题目

77. 组合

题目链接:77. 组合 - 力扣(LeetCode)

题目描述:给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

思路

直接的想法是用for循环,k为几,就嵌套几个for循环,若k很大,这一做法就变得非常繁琐复杂,所以想到用回溯法。 

上面说到要把回溯抽象成属性结构,集合的大小,n为树的宽度,而递归深度为k,是树的深度。

以n为4,k为2为例,树形结构为:

递归就是把暴力枚举法【自动化】了。我们先把数组中前k个元素纳入麾下(由不断在递归中调用递归实现,每次递归添加一个数),然后保持前k-1个数不变,把最后一个替换成新的数(当下最后一层递归因为长度等于k结束后,把最后一个元素弹出)。每次调用递归都要进行一个for循环,调用到结果集的长度为k时为止,所以就相当于进行了k此循环,只是由于递归回溯的操作,代码很简洁。

代码实现

class Solution(object):
    def backtracking(self, n, k, startindex, path, result):
        if len(path) == k:
            result.append(path[:])
            return
        for i in range(startindex, n+1):
            path.append(i)
            self.backtracking(n, k, i+1, path, result)
            path.pop()

    def combine(self, n, k):
        result = []  # 存放结果集
        self.backtracking(n, k, 1, [], result)
        return result

优化版

每次循环没必要从startindex一直遍历到数组最后的元素n。比如k=3, n=5,那么第一层到第三个数就可停止遍历,因为3之后开始最多只有两个数(4,5),小于k。遇到这类代码问题,我总是头大,纠结于区间、加1减1的问题,试着画图解释:

假设要找的个数为3,已经有了1个(即len(path) = 1),还需取2个(即k-len(path) = 2),那么最后一个能取的数字由黑色的框表示,因为从它到数组最后正好空出了2个,在它前面有n-(k-len(path))个,所以它代表的数是n-(k-len(path))+1(注意不要和数组的序号搞混,我们找的数是从1开始的),又因为Python的for循环是左闭右开的,为了能取到黑框,需再加1,因此代码为:

for i in range(startindex, n-(k-len(path)+2):

完整代码为: 

class Solution(object):
    def backtracking(self, n, k, startindex, path, result):
        if len(path) == k:
            result.append(path[:])
            return
        for i in range(startindex, n-(k-len(path))+2):
            path.append(i)
            self.backtracking(n, k, i+1, path, result)
            path.pop()
            

    def combine(self, n, k):
        result = []  # 存放结果集
        self.backtracking(n, k, 1, [], result)
        return result
        

代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值