查找从左上角到右下角的所有路径问题。以数组为参数的递归解法输出说明

Posted

技术标签:

【中文标题】查找从左上角到右下角的所有路径问题。以数组为参数的递归解法输出说明【英文标题】:Find all paths from top left to bottom right problem. Recursive solution with array as parameter output explanation 【发布时间】:2019-11-29 15:45:51 【问题描述】:

我有一个 NxN 矩阵,我想找到从左上角到右下角的所有路径,前提是只允许向下和向右移动。

我建立了一个类 Point 来保存矩阵内的坐标。


class Point

    public int x, y;

    public Point(int x, int y)
    
        this.x = x;
        this.y = y;
    

    @Override
    public String toString()
    
        return "(" + this.x + "," + this.y + ")";
    

该算法是递归的,并检查每个点的所有可能移动。

public static void findPath(int grid[][], Point start, Point end, ArrayList<Point> currentPath)

        currentPath.add(start);

        if(start.x == end.x && start.y == end.y)
        
            System.out.println(currentPath);
            return;
        

        if(start.x + 1 < grid.length)
        
            findPath(grid, new Point(start.x + 1, start.y), end, currentPath);
        

        if(start.y + 1 < grid[0].length)
        
            findPath(grid, new Point(start.x, start.y + 1), end, currentPath);
        


对于一个简单的 2x2 矩阵,我得到以下输出:

[(0,0), (1,0), (1,1)]
[(0,0), (1,0), (1,1), (0,1), (1,1)]

预期的输出是:

[(0,0), (1,0), (1,1)]
[(0,0), (0,1), (1,1)]

看起来点(1,0),(1,1)从堆栈中弹出后,堆栈帧中的变量currentPath与点(0,0),也包含点(1,0) , (1,1) 来自之前的堆栈帧。

我主要对这种行为的解释感兴趣,因为互联网上有很多资源可以解决这个问题。是否与 currentPath 在堆上分配并且只有指向该地址的指针存储在堆栈上的事实有关?

谢谢。

【问题讨论】:

【参考方案1】:

currentPath 局部变量仅引用了一个 ArrayList 实例,因此当您将该变量传递给递归调用时,您传递的是同一个实例。

由于您只是向 ArrayList 添加元素,因此之前添加的任何元素都不会被删除,因此您可以在示例中看到两条路径的点。

您应该在完成后从ArrayList 中删除您添加的每个点,或者您可以将ArrayList 的副本传递给每个递归调用:

public static void findPath(int grid[][], Point000 start, Point000 end, ArrayList<Point000> currentPath)

    currentPath.add(start);

    if(start.x == end.x && start.y == end.y)
    
        System.out.println(currentPath);
        return;
    

    if(start.x + 1 < grid.length)
    
        findPath(grid, new Point000(start.x + 1, start.y), end, new ArrayList<>(currentPath));
    

    if(start.y + 1 < grid[0].length)
    
        findPath(grid, new Point000(start.x, start.y + 1), end, new ArrayList<>(currentPath));
    


现在输出将是:

[(0,0), (1,0), (1,1)]
[(0,0), (0,1), (1,1)]

【讨论】:

感谢您的出色回答。你能解释一下为什么在每次递归调用时传递数组的副本可以解决问题吗? @AdrianNegru 如果您将列表的副本传递给递归调用,则一旦递归调用返回,递归调用对该副本所做的任何更改都不会影响原始列表。因此两个递归调用您的方法将收到具有相同元素的列表。

以上是关于查找从左上角到右下角的所有路径问题。以数组为参数的递归解法输出说明的主要内容,如果未能解决你的问题,请参考以下文章

从矩阵的左上角到右下角找到路径的最快方法

通过矩阵查找所有路线

迷宫问题

从左上到右下排序坐标

计算二维数组上的路径数(网格旅行者)

11.迷宫问题(BFS 储存路径)