如何将查找矩阵中所有可能路径的递归函数转换为迭代函数?

如何解决如何将查找矩阵中所有可能路径的递归函数转换为迭代函数?

我有一个函数可以找到从矩阵的左上角到右下角单元格的所有可能路径,向右、向下或对角移动以找到路径。

现在,我想将其转换为迭代函数,以便我以后可以更轻松地进行调整。有谁知道我该怎么做?

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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?