Arrays 递归遍历二维数组以找到唯一路径

Arrays 递归遍历二维数组以找到唯一路径,arrays,algorithm,recursion,Arrays,Algorithm,Recursion,我需要遍历由0(表示开放路径)和1(表示墙)组成的二维数组。我必须计算从NxN网格的(0,0)到(N-1,N-1)的唯一路径的数量。我已经编写了一个递归方法来实现这一点,但是我无法理解为什么我的方法的遍历部分(即直线、左和右移动)没有按预期工作: public static void TraversePath(int [][] Grid, boolean[][] isTraversed, int column, int row) { if(row < 0 || column

我需要遍历由0(表示开放路径)和1(表示墙)组成的二维数组。我必须计算从NxN网格的(0,0)到(N-1,N-1)的唯一路径的数量。我已经编写了一个递归方法来实现这一点,但是我无法理解为什么我的方法的遍历部分(即直线、左和右移动)没有按预期工作:

    public static void TraversePath(int [][] Grid, boolean[][] isTraversed, int column, int row) {
    if(row < 0 || column < 0 || row > Grid[0].length || column > Grid[0].length )
        return; // if you go out of bounds
    if(isTraversed[column][row] == true)
        return; // if you have already been to the point
    if(Grid[column][row]==1) {
        isTraversed[column][row] = true; // if the current point is a wall mark it as traversed
        return;
    }
    if(Grid[column][row]!=1 && (row == Grid[0].length-1 && column == Grid[0].length-1)) { //if you get to an endpoint that isn't a wall
        uniquePaths++; //counter that tallys the unique paths
        isTraversed[column][row] = true;
        return;
    }

    TraversePath(Grid,column,row+1);//Straight
    TraversePath(Grid,column-1, row);//Left
    TraversePath(Grid,column+1, row);//Right

}



public static void main(String[] args) {
    int [][]Grid = new int[][]
            {
        {0,1,1,0},
        {0,0,1,0},
        {0,0,0,0},
        {0,1,1,0}
            };
    boolean[][] isTraversed = new boolean[Grid.length][Grid.length];
    for(int i = 0; i < Grid.length; i++) {
        for(int j = 0; j< Grid.length; j++)
            isTraversed[i][j] = false;
    }
    TraversePath(Grid,isTraversed,0,0);
    System.out.println(uniquePaths);

} 
publicstaticvoidtransversePath(int[][]网格,boolean[]]isTraversed,int列,int行){
if(行<0 | |列<0 | |行>网格[0]。长度| |列>网格[0]。长度)
return;//如果你越界了
如果(isTraversed[列][行]==true)
return;//如果您已经说到点子上了
if(网格[列][行]==1){
isTraversed[列][行]=true;//如果当前点是墙,则将其标记为已遍历
返回;
}
如果(网格[column][row]!=1&&(row==Grid[0].length-1&&column==Grid[0].length-1)){//如果到达的端点不是墙
UniquePath++;//统计唯一路径的计数器
isTraversed[列][行]=true;
返回;
}
TraversePath(网格、列、行+1);//直线
TraversePath(网格,列-1,行);//左
TraversePath(网格,列+1,行);//右
}
公共静态void main(字符串[]args){
int[][]网格=新int[][]
{
{0,1,1,0},
{0,0,1,0},
{0,0,0,0},
{0,1,1,0}
};
boolean[][]isTraversed=新的boolean[Grid.length][Grid.length];
对于(int i=0;i
当我运行这段代码时,我一直会遇到StackOverFlow错误(嘿,听起来很熟悉)。我想这可能与我如何标记isTraversed布尔图中访问的边有关,但我不确定。任何帮助都将不胜感激


这是我用来测试数组的主要方法,它是一个简单的4x4网格,有两条到(3,3)的唯一路径。

这段代码中有几个错误,但主要的问题是,如果您只是执行一个正常步骤而没有运行任何if语句,您就没有设置
isTraversed[column][row]=true

另一个大问题是,
isTraversed
数组在不同的搜索路径上共享。这意味着在迭代的一个分支中访问的网格字段不能在另一个分支中访问。最终,您的结果将始终最多为1。为了避免这种情况,您可以在进入下一个迭代步骤之前,制作一个深度拷贝
isTraversed

boolean[][] isTraversedCopy = new boolean[isTraversed.length][isTraversed[0].length];
for(int i=0; i<isTraversed.length; i++)
      for(int j=0; j<isTraversed[i].length; j++)
          isTraversedCopy[i][j]=isTraversed[i][j];

TraversePath(Grid,isTraversedCopy, column,row+1);//Straight
TraversePath(Grid,isTraversedCopy, column-1, row);//Left
TraversePath(Grid,isTraversedCopy, column+1, row);//Right
boolean[][]isTraversedCopy=new boolean[isTraversed.length][isTraversed[0.length];
对于(int i=0;i=Grid[0]。长度)
  • 为什么没有向底部移动的可能性
  • 可选,但这将使代码的可读性更容易:您应该更改行和列,使其与gridworld的表示一致,并与2d数组的正常使用一致。此外,直线、左、右的定义有点混乱,不适合网格定义
    您的
    堆栈溢出
    错误是由于您可以连续向左再向右移动而导致的。假设您只能正向移动,您可以使用动态编程生成一个非常简单的递归函数,以防止出现
    堆栈溢出
    错误

    public static int possiblePaths(int[][] grid, int x,int y,int [][] dp){
        if(x<0||x>=grid.length||y<0||y>=grid[0].length)
            return 0;
        if(dp[x][y]==-1){
            dp[x][y]=possiblePaths(grid,x+1,y,dp)+possiblePaths(grid,x,y+1,dp);
        }
        return dp[x][y];
    }
    
    public static void main(String[] args) {
        int [][]Grid = new int[][]
                {
            {0,1,1,0},
            {0,0,1,0},
            {0,0,0,0},
            {0,1,1,0}
                };
        int [][] dp = new int[Grid.length][Grid[0].length];
        for(int i = 0; i < Grid.length; i++) {
            for(int j = 0; j< Grid[0].length; j++)
                if(Grid[i][j]==1)
                    dp[i][j]=0;
                else
                    dp[i][j]=-1;
        }
        dp[Grid.length-1][Grid[0].length-1]=0;
        System.out.println(possiblePaths(Grid,0,0,dp));
    
    } 
    
    公共静态int可能路径(int[][]网格、int x、int y、int[][]dp){
    如果(x=网格。长度| | y=网格[0]。长度)
    返回0;
    如果(dp[x][y]=-1){
    dp[x][y]=可能路径(网格,x+1,y,dp)+可能路径(网格,x,y+1,dp);
    }
    返回dp[x][y];
    }
    公共静态void main(字符串[]args){
    int[][]网格=新int[][]
    {
    {0,1,1,0},
    {0,0,1,0},
    {0,0,0,0},
    {0,1,1,0}
    };
    int[][]dp=new int[Grid.length][Grid[0.length];
    对于(int i=0;i

    这基本上说明了从
    (x,y)
    到最后的路径数是
    (x+1,y)
    路径数和
    (x,y+1)
    路径数之和,并在dp(动态编程)数组中记住这些数字,因此不需要重新计算它们。在dp数组中,有墙的单元格设置为0,因为有0种方法可以从墙到达终点。

    可能会有帮助。。。您正在检查
    网格[column][row]==1
    ,但它从未赋值1。只是验证一下-您已经编写了可以在三个方向上运行的代码,即。直,左,右。我所看到的关于这个问题的所有变体都只允许向右(或向左)和向下(或向上)移动。当您使用DP时,在问题中OP编写了允许在三个方向(直线、向右和向左)移动的代码。使用DP,你只能在两个方向上行驶。就像我说的,如果你能够在三个方向上行驶,那么会有无限多的路径,因为你可以反复向左和向右行驶不同的次数。这也是堆栈溢出错误的最可能原因。因此,我认为这是对问题的误解。我的错误。我没有通读整个答案,而是看到了你面向DP的代码并发表了评论。嘿,非常感谢你,这是一个如此简单优雅的问题解决方案,我希望我能够更递归地思考。出于好奇,这种算法的时间复杂度是多少?我从来没有考虑过时间的复杂性