如何解决如何将查找矩阵中所有可能路径的递归函数转换为迭代函数?
我有一个函数可以找到从矩阵的左上角到右下角单元格的所有可能路径,向右、向下或对角移动以找到路径。
现在,我想将其转换为迭代函数,以便我以后可以更轻松地进行调整。有谁知道我该怎么做?
def findpaths(mat,path,i,j):
(M,N) = (len(mat),len(mat[0]))
# if we have reached the last cell,print the route
if i == M - 1 and j == N - 1:
#print('finish')
print(path + [mat[i][j]])
return
# include current cell in path
path.append(mat[i][j])
# move right
if 0 <= i < M and 0 <= j + 1 < N:
#print('right',j)
findpaths(mat,j + 1)
# move down
if 0 <= i + 1 < M and 0 <= j < N:
#print('down',i + 1,j)
# move diagonal
if 0 <= i + 1 < M and 0 <= j + 1 < N:
#print('diagonal',j + 1)
# remove current cell from path
path.pop()
if __name__ == '__main__':
mat = [
[1,2,6],[4,5,7],[7,8,9]
]
path = []
# start from (0,0) cell
x = y = 0
findpaths(mat,x,y)
解决方法
递归使它更容易,因为您可以与调用堆栈一起推入和弹出路径列表。这是内存友好的,因为产生解决方案的副本只发生在最后,然后相同的中间路径列表被重用于所有其他路径。
顺便说一句,我建议在终端节点使用 yield path[:]
而不是 print
以便调用者除了打印之外还可以自由地以编程方式使用结果,从而使该函数更具通用性。您还需要 yield from findPaths...
来实现这一点。
另外,注意索引到可能为空的列表中。
这个特定问题可能有一个组合解决方案(请参阅 Project Euler #15),但这并不能真正帮助图中所有路径的一般情况,所以我没有研究它。
对于像这样的典型动态规划问题,您可以使用两个循环执行自下而上的解决方案,这对于计算 dp[-1][-1]
处的结果数量非常有用,但对于存储一个整体没有那么有用每个节点的每条可能路径的列表,即使您从 i - 2,j - 2
处不再有用的中间状态分配/取消分配列表。
此重构的典型模式是一个显式堆栈,用于跟踪所有路径。这是您的代码与典型迭代版本一起重写的代码(仍有优化空间,将其视为概念验证):
def find_paths_rec(mat,x=0,y=0,path=None):
if not mat or not mat[y]:
return
elif not path:
path = []
dirs = (1,0),(0,1),(1,M,N = len(mat),len(mat[y])
path.append(mat[y][x])
if y == M - 1 and x == N - 1:
yield path[:]
else:
for xx,yy in dirs:
xx += x
yy += y
if yy < M and xx < N:
yield from find_paths_rec(mat,xx,yy,path)
path.pop()
def find_paths_it(mat,y=0):
dirs = (1,stack = [((x,y),(mat[y][x],))]
while stack:
(x,path = stack.pop()
if y == len(mat) - 1 and x == len(mat[y]) - 1:
yield path
else:
for xx,yy in dirs:
xx += x
yy += y
if yy < len(mat) and xx < len(mat[yy]):
stack.append(((xx,yy),path + (mat[yy][xx],)))
if __name__ == "__main__":
from timeit import timeit
mat = [
[1,2,6],[4,5,7],[7,8,9],]
for fn in find_paths_it,find_paths_rec:
print(fn.__name__,timeit(lambda: fn(mat,0)))
for path in fn(mat,0):
print(path)
print()
输出:
find_paths_it 0.9263676
(1,6,7,9)
(1,4,9)
find_paths_rec 0.9654003
[1,9]
[1,9]
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。