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
-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 )
这就是(按时间顺序)回溯的全部内容。只需嵌套循环,每个循环保持其状态,当控件返回(回溯)到它时,准备尝试另一种选择
还有,这就是“单子”都是关于。只需广义嵌套循环,从最深的循环内部串联产生输出,而不管它上面有多少层。在这段代码中,append
扮演着push
的角色。函数调用的工作原理完全相同,无论它们是递归的还是非递归的不是。curr.pop()
正在删除列表中的最后一项,即i
,因为它是与curr.append(i)
一起添加的。