递归回溯法经典——组合(python)

关于递归,虽然每次看代码都能明白别人代码的大体意思,但实际上当自己动手写的时候,往往没有头绪。

为了解决这个问题,我感觉我们需要深入探究模拟别人代码的全过程,了解递归回溯的基本像树一样的全过程,才能帮助我们更好的理解,当然写这篇文章也是给自己一个记录复习,可能无法实质性的帮助到大家哈哈哈哈

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

把组合问题抽象为如下树形结构

然后下面的回溯三部曲大家应该也明白,我再赘述一下:

  • 递归函数的返回值以及参数
  • 回溯函数终止条件
  • 单层搜索的过程

这里我直接贴出卡尔老师的代码,因为代码的浅理解也比较容易

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        res = []
        path = []
        def backtrack(n, k, StartIndex):
            if len(path) == k:
                res.append(path[:])
                return
            for i in range(StartIndex, n + 1):
                path.append(i)
                backtrack(n, k, i+1)
                path.pop()
        backtrack(n, k, 1)
        return res

下面也就是本博客主要的出发点:模拟程序运行的过程——

建议大家结合着画着二叉树来模拟

当n=4和k=2时,程序的完整具体运行过程如下:

  1. 初始化res为空列表,初始化path为空列表。

  2. 调用backtrack函数,传递参数n=4,k=2,StartIndex=1。

  3. 判断如果当前path列表中的元素数量等于k,将其复制一份并添加到res列表中,并立即返回。

  4. 进入for循环,循环变量i从StartIndex(1开始)到n+1(5),依次取值为1, 2, 3, 4.

  5. 在每个for循环迭代中,将变量i添加到path列表中。

  6. 调用backtrack函数,传递参数n=4,k=2,StartIndex=i+1(i的初始值为1,则第一次调用将传递2作为StartIndex参数)。

  7. 重复步骤3到步骤6,直到path列表中的元素数量等于k。

  8. 当path列表中的元素数量等于k时,将其复制一份并添加到res列表中,并立即返回上一级backtrack函数的调用。

  9. 回溯,将最后一个添加到path列表中的元素弹出。

  10. 回到步骤5,继续循环。重复步骤5到步骤9,直到所有迭代结束。

  11. 返回res列表作为输出结果。

接下来是更具体的过程以下为chatgpt所写,可能略有出入,但大体的思路见解可以供我们参考,当我们理解里面的总体过程,我们也就对回溯法有了进一步的认识

当 n=4, k=2 时,程序的运行过程如下:

  1. 首先初始化结果列表 res 和路径列表 path。

    res = [] path = []

  2. 调用 backtrack 函数,并传入参数 n=4, k=2, StartIndex=1。

    执行 backtrack(n=4, k=2, StartIndex=1)。

  3. 判断当前路径长度是否等于 k,如果是则将当前路径添加到结果列表中并返回。

  4. 对于循环中的每个 i,执行以下操作:

    a. 将 i 添加到路径列表 path 中。

    b. 递归调用 backtrack 函数,传入参数 n、k、i+1。

    • 当 i=1 时,执行 backtrack(n=4, k=2, StartIndex=2)。

      • 判断当前路径长度是否等于 k,长度为 1 不等于 k,继续执行。

      • 对于循环中的每个 j,在路径中加入 j 并递归调用 backtrack 函数,传入参数 n、k、j+1。由于此时 k=2,因此只需要找到两个数即可,所以 j 的取值范围为 [2, 4]。

        • 当 j=2 时,执行 backtrack(n=4, k=2, StartIndex=3)。

          • 判断当前路径长度是否等于 k,长度为 2 等于 k,将路径 [1,2] 添加到结果列表中。
        • 当 j=3 时,执行 backtrack(n=4, k=2, StartIndex=4)。

          • 判断当前路径长度是否等于 k,长度为 2 等于 k,将路径 [1,3] 添加到结果列表中。
        • 当 j=4 时,由于此时已经没有元素可以添加到路径中,直接返回。

    • 当 i=2 时,执行 backtrack(n=4, k=2, StartIndex=3)。

      • 判断当前路径长度是否等于 k,长度为 1 不等于 k,继续执行。

      • 对于循环中的每个 j,在路径中加入 j 并递归调用 backtrack 函数,传入参数 n、k、j+1。由于此时 k=2,因此只需要找到两个数即可,所以 j 的取值范围为 [3, 4]。

        • 当 j=3 时,执行 backtrack(n=4, k=2, StartIndex=4)。

          • 判断当前路径长度是否等于 k,长度为 2 等于 k,将路径 [2,3] 添加到结果列表中。
        • 当 j=4 时,由于此时已经没有元素可以添加到路径中,直接返回。

    • 当 i=3 时,执行 backtrack(n=4, k=2, StartIndex=4)。

      • 判断当前路径长度是否等于 k,长度为 1 不等于 k,继续执行。

      • 对于循环中的每个 j,在路径中加入 j 并递归调用 backtrack 函数,传入参数 n、k、j+1。由于此时 k=2,因此只需要找到两个数即可,所以 j 的取值范围为 [4]。

        • 当 j=4 时,由于此时已经没有元素可以添加到路径中,直接返回。
    • 当 i=4 时,由于此时已经没有元素可以添加到路径中,直接返回。

  5. backtrack 函数执行完毕后,将结果列表 res 返回。

    所以最终的输出结果为 [[1, 2], [1, 3], [2, 3], [1, 4], [2, 4], [3, 4]]。

参考大佬的这篇文章:代码随想录 (programmercarl.com)https://www.programmercarl.com/0077.%E7%BB%84%E5%90%88.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值