为什么我们在每次回溯迭代结束时从列表中弹出?

用户15740803

我有以下问题的解决方案:https : //leetcode.com/problems/combinations/

List[List[int]]:
        def backtrack(first = 1, curr = []):
            # if the combination is done
            if len(curr) == k:  
                output.append(curr[:])
            for i in range(first, n + 1):
                # add i into the current combination
                curr.append(i)
                # use next integers to complete the combination
                backtrack(i + 1, curr)
                # backtrack
                curr.pop()
        
        output = []
        backtrack()
        return output

我的问题是curr.pop()为什么我们curr每次迭代都要弹出组合?不应该有一些条件,比如 ifcurr已经在输出中吗?

另一个问题是递归调用backtrack(i+1, curr)- 当调用它时,我说' i+1'代替' first'在主函数中是否正确?

威尔·尼斯

组合的(副本)在递归curr最深 层次输出(嗯,它应该是最深的,目前代码继续循环,即使事先知道它是徒劳的,即没有机会产生任何输出,即当的长度curr大于k)。

这种组合是建立在方式上的,一次一个元素。

添加元素,进入递归(最终达到最深层次,将组合的副本收集到输出中),然后递归展开,最终退出递归调用 --- 所以我们必须删除元素我们已经投入了,所以我们可以把下一个元素进入curr,对下一个迭代是的for ... range ...循环(这应该由看守if len(curr) < k: ....)。

所以是的,i+1 -在下一个循环中,更深一层“新”因此,这里发生的事情是递归实际上构建了嵌套循环结构,其中最深的循环具有完全设置和填充,因此将其添加到.first for ... range ...curroutput

或者用伪代码:

   for i1 in range( 1, n+1):
      for i2 in range( i1+1, n+1):
         .........
            for ik in range( ik1+1, n+1):
               output.append( [i1,i2,...,ik1,ik] )

(除了您的代码效率低下,它不断为k+1, k+2, ...,n级别创建更多循环,即使我们已经知道这一切都是徒劳的,因为我们只需要 length 的组合k)。

这是它的要点,尽管您的代码没有curr在最深层次构建while,如上所示,而是通过在每个 ( th) 级别附加这就是为什么在从循环中附加下一个值之前需要的原因,实际上是更新中第 th 位置ijjpopforjcurr

   for i1 in range( 1, n+1):
      curr.append(i1)
      for i2 in range( i1+1, n+1):
         curr.append(i2)
            .........
               for ik in range( ik1+1, n+1):
                  curr.append(ik)
                  output.append( curr )
                  curr.pop()
            .........
         curr.pop()
      curr.pop()

直接改变jth值也可以达到同样的效果curr您需要为此创建k-longcurr前期(最初填充一些不重要的值),并为此引入一个额外的计数器:

   for i1 in range( 1, n+1):
      curr[0] = i1                             # j == 0
      for i2 in range( i1+1, n+1):
         curr[1] = i2                          # j == 1
            .........
               for ik in range( ik1+1, n+1):
                  curr[k-1] = ik               # j == k-1
                  output.append( curr )

这就是(按时间顺序)回溯的全部意义所在。只是嵌套循环,每个循环保持其状态,准备在控件返回(回溯)时尝试另一种选择。

此外,这就是“monads”的全部含义只是广义的嵌套循环,协同工作以从最深的内部产生输出无论它上面有多少层。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么我的成员变量在每次循环迭代结束时消失?

我们是否需要在生产结束时捆绑我们的js文件

为什么我们建议使用迭代器而不是列表(低级解释)

当我们编辑(追加,删除...)列表时会发生什么,每次编辑列表时我们都可以执行操作吗?

为什么在Scala中创建列表时我们需要Nil?

为什么每次我们需要在TensorFlow中运行某些东西时都构建bazel?

为什么我们需要以“ Nil”结尾的列表

为什么要用改造时,我们有OkHttp

为什么我们在休息时使用原子?

为什么等待延迟在功能范围结束时结束

如何在程序结束时和每次迭代结束时一路输出结果?

为什么我们同时需要迭代和迭代器概念?

为什么我不能在每个 epoch 结束时执行验证测试?

为什么我的代码在测验结束时不显示分数?

为什么我们保留互斥锁而不是每次都在警惕之前声明它?

在 goLang 中,为什么我们每次都在 for 循环中创建通道

为什么我们使用“/”来标记 MySQL 查询的结束?

为什么jvm每次我们使用new关键字创建字符串时都会创建新字符串对象

为什么每次我们在处理netbeans数据库(JDBC)时都需要将驱动程序复制到项目中

为什么我们使用entrySet()方法并使用返回的集来迭代地图?

为什么我们需要在Java中对ArrayList使用迭代器?

为什么我们不能添加带有整数的迭代器?

我们为什么不实现Iterator的所有功能来实现迭代器?

为什么我们不能使用push方法来迭代javascript数组?

为什么我们将 ::(范围解析运算符)放在迭代器之前?

为什么我们不在 stl 的迭代器中传递星号(*)

为什么 dockerized zap 在基线扫描结束时挂起?

为什么在功能结束时仍然借用“数据”?

每次最后结束时就开始循环