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

Python 为什么我们会在每次回溯迭代结束时从列表中弹出?,python,recursion,recursive-backtracking,Python,Recursion,Recursive Backtracking,我有以下问题的解决方案: List[List[int]]: def回溯(第一个=1,当前=[]): #如果组合完成 如果len(curr)==k: output.append(curr[:]) 对于范围内的i(第一,n+1): #将i添加到当前组合中 货币附加(一) #使用下一个整数完成组合 回溯(i+1,当前) #回溯 流行音乐 输出=[] 回溯 返回输出 我的问题是关于curr.pop()为什么每次迭代都要弹出curr组合?如果输出中已经存在curr,是否应该存在这样的条件 另一个问题是递

我有以下问题的解决方案:

List[List[int]]:
def回溯(第一个=1,当前=[]):
#如果组合完成
如果len(curr)==k:
output.append(curr[:])
对于范围内的i(第一,n+1):
#将i添加到当前组合中
货币附加(一)
#使用下一个整数完成组合
回溯(i+1,当前)
#回溯
流行音乐
输出=[]
回溯
返回输出
我的问题是关于
curr.pop()
为什么每次迭代都要弹出
curr
组合?如果输出中已经存在
curr
,是否应该存在这样的条件

另一个问题是递归调用
backtrack(i+1,curr)
——调用时,我说的“
i+1
”代替主函数中的“
first
”,对吗?

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

这种组合是在一次一个元素的过程中构建的

元素被添加,递归被输入(最终达到最深的级别,组合的副本被收集到输出中)然后递归展开,最终退出递归调用——因此我们必须删除我们放入的元素,这样我们就可以将下一个元素放入
curr
,在该
for…range…
循环的下一次迭代中(应该由
if len(curr)
保护)

是的,
i+1
是“新的”
first
的值——在下一个
中,对于…范围…
循环,更深一层。因此,这里发生的是递归实际上构建了嵌套循环结构,其中最深的循环将
curr
完全设置和填充,并将其添加到
输出中

或使用伪代码:

   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
级别创建更多循环,即使我们已经知道这一切都是徒劳的,因为我们只需要长度
k
的组合)

这是它的要点,尽管您的代码在最深层次上没有构建
curr
,如上所示,而是通过在每个(
j
th)处追加
ij
)级别。这就是为什么它需要在添加
for
循环的下一个值之前
弹出它,实际上更新
curr
中的
j
th位置:

   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()
直接更改
curr
中的
j
th值也可以达到同样的效果。您需要为该值预先创建
k
-long
curr
(最初填充一些不重要的值),并为此引入一个额外的计数器:

   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 )
这就是(按时间顺序)回溯的全部内容。只需嵌套循环,每个循环保持其状态,当控件返回(回溯)到它时,准备尝试另一种选择


还有,这就是“单子”
都是关于。只需广义嵌套循环,从最深的循环内部串联产生输出,而不管它上面有多少层。

在这段代码中,
append
扮演着
push
的角色。函数调用的工作原理完全相同,无论它们是递归的还是非递归的不是。
curr.pop()
正在删除列表中的最后一项,即
i
,因为它是与
curr.append(i)
一起添加的。