Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在NxN网格中查找所有路径的算法_Java_Algorithm - Fatal编程技术网

Java 在NxN网格中查找所有路径的算法

Java 在NxN网格中查找所有路径的算法,java,algorithm,Java,Algorithm,想象一个机器人坐在NxN网格的左上角。机器人只能向两个方向移动:向右和向下。机器人有多少条可能的路径 我可以在谷歌上找到这个问题的解决方案,但我不太清楚其中的解释。我试图清楚地理解如何解决这个问题并用Java实现的逻辑。感谢您的帮助 更新:这是一个面试问题。现在,我正在尝试到达右下角并打印可能的路径。int N; int N; function num_paths(intx,int y) { int[][] arr = new int[N][N]; arr[N-1][N-1] = 0;

想象一个机器人坐在NxN网格的左上角。机器人只能向两个方向移动:向右和向下。机器人有多少条可能的路径

我可以在谷歌上找到这个问题的解决方案,但我不太清楚其中的解释。我试图清楚地理解如何解决这个问题并用Java实现的逻辑。感谢您的帮助

更新:这是一个面试问题。现在,我正在尝试到达右下角并打印可能的路径。

int N;
int N;
function num_paths(intx,int y)
{
    int[][] arr = new int[N][N];
arr[N-1][N-1] = 0;
for(int i =0;i<N;i++)
{
    arr[N-1][i]=1;
    arr[i][N-1]=1;
}
for(int i = N-2;i>=0;i--)
{
    for(int j=N-2;j>=0;j--)
    {
        arr[i][j]= arr[i+1][j]+arr[i][j+1];
    }
}
return arr[0][0];
 }
函数num_路径(intx,inty) { int[]arr=新的int[N][N]; arr[N-1][N-1]=0; 对于(int i=0;i=0;i--) { 对于(int j=N-2;j>=0;j--) { arr[i][j]=arr[i+1][j]+arr[i][j+1]; } } 返回arr[0][0]; }
我看不到您的问题中有任何障碍,因此我们可以假设没有障碍

请注意,对于n+1乘n+1网格,机器人需要精确地执行
2n
步才能到达右下角。因此,它最多只能进行
2n次
移动

让我们从一个简单的例子开始:[找到右下角的所有路径]

机器人能准确地做出
=(2n)/(n!*n!)
路径:它只需要选择
2n
移动中的哪一个是正确的,其余的是向下的(这些路径中正好有
n
)。
要生成可能的路径:只需生成大小为
2n
的所有二进制向量,精确地
n
1。1表示向右移动,0表示向下移动

现在,让我们将其扩展到所有路径:
首先选择路径的长度。为此,迭代所有可能性:
0-看看我的解决方案。似乎这正是您所需要的(是的,语句略有不同,但在一般情况下它们是相同的)

查找所有可能的路径:
仍然使用递归方法。一个路径变量在开头指定为“”,然后将访问的每个点添加到“路径”。到达(n,n)点时形成一个可能的路径,然后将其添加到列表中。

每个路径都表示为字符串,例如“(1,1)(2,1)(3,1)(4,1)(4,2)(4,3)(4,4)”。所有可能的路径都存储在字符串列表中

public static List<String> robotPaths(int n){
    List<String> pathList = new ArrayList<String>();
    getPaths(n, 1,1, "", pathList);
    return pathList;
}
public static void getPaths(int n, int i, int j, String path, List<String> pathList){
    path += String.format(" (%d,%d)", i , j);
    if( i ==n && j == n){ //reach the (n,n) point
        pathList.add(path);
    }else if( i > n || j > n){//wrong way
        return;
    }else {
        getPaths(n, i +1, j , path, pathList);
        getPaths(n, i , j +1, path, pathList);
    }
}
公共静态列表机器人路径(int n){
列表路径列表=新的ArrayList();
获取路径(n,1,1,“,路径列表);
返回路径列表;
}
公共静态void getpath(int n、int i、int j、字符串路径、列表路径列表){
path+=String.format((%d,%d)”,i,j);
如果(i==n&&j==n){//到达(n,n)点
添加(路径);
}如果(i>n | | j>n){//错误的方式
返回;
}否则{
获取路径(n,i+1,j,路径,路径列表);
获取路径(n,i,j+1,路径,路径列表);
}
}
场景:
1.假设存在NxN零索引矩阵。
2.机器人的初始位置在左上角,即(N-1,N-1)
3.机器人想要到达右下角,即(0,0)

解决方案:
--在任何可能的解决方案中,robot将移动N个权限步骤和N个向下步骤以达到(0,0),或者我们可以说初始robot有权移动N个权限步骤和N个向下步骤。
--当机器人向右移动时,我们将其剩余的向右步数减少1,向下移动也是如此。
--在每一个位置(除了边界处,它只有一个选项),机器人都有两个选项,一个是它可以向下移动,另一个是它可以向右移动。
--当机器人没有剩余的正确步骤时,它将终止。

**下面的代码还有驱动程序方法main(),您可以更改N的值。N可以>=1

public class RobotPaths {

public static int robotPaths(int down, int right, String path)
{
    path = path+ down +","+ right +"  ";
    if(down==0 && right==0)
    {
        System.out.println(path);
        return 1;
    }

    int counter = 0;

    if(down==0)
        counter = robotPaths(down, right-1, path);
    else if(right==0)
        counter = robotPaths(down-1, right, path);
    else
        counter = robotPaths(down, right-1, path) + robotPaths(down-1, right, path);

    return counter;
}

public static void main(String[] args) 
{
    int N = 1;
    System.out.println("Total possible paths: "+RobotPaths.robotPaths(N-1, N-1, ""));

}
}

这里是查找唯一路径的c#version(仅供参考)(请注意,这里是使用动态编程(记忆-惰性)返回路径数的版本)(有关更多详细信息,请参阅我的博客:)

Tuple[]getUniquePath(int N)
{
var r=this.getUniquePath(1,1,N);
返回r;
}
私有元组[][]GetUniquePath(int行、int列、int N)
{
如果((行==N)和&(列==N))
{
var r=新元组[1][];
r[0]=新元组[]{新元组(行、列)};
返回r;
}
如果((行>N)| |(列>N))
{
返回新元组[0][];
}
var uniquepath sbymovingdown=this.getuniquepath(行+1,列,N);
var uniquePathsByMovingRight=this.getuniquepath(行、列+1,N);
List path=this.mergepath(uniquePathsByMovingDown,
行、列);
paths.AddRange(this.MergePaths(uniquePathsByMovingRight,row,column));
返回路径。ToArray();
}
其中

private Tuple<int, int>[][] MergePaths(Tuple<int, int>[][] paths, 
            int row, int column)
        {
            Tuple<int, int>[][] mergedPaths = new Tuple<int, int>[paths.Length][];
            if (paths.Length > 0)
            {
                Assert.IsTrue(paths.All(p => p.Length > 0));
                for (int i = 0; i < paths.Length; i++)
                {
                    List<Tuple<int, int>> mergedPath = new List<Tuple<int, int>>();
                    mergedPath.Add(new Tuple<int, int>(row, column));
                    mergedPath.AddRange(paths[i]);
                    mergedPaths[i] = mergedPath.ToArray();
                }
            }
            return mergedPaths;
        }
私有元组[][]合并路径(元组[][]路径,
整数行,整数列)
{
元组[][]合并路径=新元组[path.Length][];
如果(路径长度>0)
{
IsTrue(path.All(p=>p.Length>0));
for(int i=0;i
单元测试

[TestCategory(Constants.DynamicProgramming)]
        public void RobotInGridTests()
        {
            int p = this.GetNumberOfUniquePaths(3);
            Assert.AreEqual(p, 6);
            int p1 = this.GetUniquePaths_DP_Memoization_Lazy(3);
            Assert.AreEqual(p, p1);
            var p2 = this.GetUniquePaths(3);
            Assert.AreEqual(p1, p2.Length);
            foreach (var path in p2)
            {
                Debug.WriteLine("===================================================================");
                foreach (Tuple<int, int> t in path)
                {
                    Debug.Write(string.Format("({0}, {1}), ", t.Item1, t.Item2));
                }
            }
            p = this.GetNumberOfUniquePaths(4);
            Assert.AreEqual(p, 20);
            p1 = this.GetUniquePaths_DP_Memoization_Lazy(4);
            Assert.AreEqual(p, p1);
            p2 = this.GetUniquePaths(4);
            Assert.AreEqual(p1, p2.Length);
            foreach (var path in p2)
            {
                Debug.WriteLine("===================================================================");
                foreach (Tuple<int, int> t in path)
                {
                    Debug.Write(string.Format("({0}, {1}), ", t.Item1, t.Item2));
                }
            }
        }
[TestCategory(Constants.DynamicProgramming)]
公共无效机器人测试()
{
int p=this.getNumberOfUniquePath(3);
断言:AreEqual(p,6);
int p1=this.getuniquepath\u DP\u memorization\u Lazy(3);
断言:AreEqual(p,p1);
var p2=this.getUniquePath(3);
断言.AreEqual(p1,p2.长度);
foreach(p2中的变量路径)
Tuple<int, int>[][] GetUniquePaths(int N)
        {
            var r = this.GetUniquePaths(1, 1, N);
            return r;
        }
        private Tuple<int, int>[][] GetUniquePaths(int row, int column, int N)
        {
            if ((row == N) && (column == N))
            {
                var r = new Tuple<int, int>[1][];
                r[0] = new Tuple<int, int>[] { new Tuple<int,int>(row, column) };
                return r;
            }
            if ((row > N) || (column > N))
            {
                return new Tuple<int, int>[0][];
            }
            var uniquePathsByMovingDown = this.GetUniquePaths(row + 1, column, N);
            var uniquePathsByMovingRight = this.GetUniquePaths(row, column + 1, N);
            List<Tuple<int, int>[]> paths = this.MergePaths(uniquePathsByMovingDown,
                row, column).ToList();
            paths.AddRange(this.MergePaths(uniquePathsByMovingRight, row, column));
            return paths.ToArray();
        }
private Tuple<int, int>[][] MergePaths(Tuple<int, int>[][] paths, 
            int row, int column)
        {
            Tuple<int, int>[][] mergedPaths = new Tuple<int, int>[paths.Length][];
            if (paths.Length > 0)
            {
                Assert.IsTrue(paths.All(p => p.Length > 0));
                for (int i = 0; i < paths.Length; i++)
                {
                    List<Tuple<int, int>> mergedPath = new List<Tuple<int, int>>();
                    mergedPath.Add(new Tuple<int, int>(row, column));
                    mergedPath.AddRange(paths[i]);
                    mergedPaths[i] = mergedPath.ToArray();
                }
            }
            return mergedPaths;
        }
[TestCategory(Constants.DynamicProgramming)]
        public void RobotInGridTests()
        {
            int p = this.GetNumberOfUniquePaths(3);
            Assert.AreEqual(p, 6);
            int p1 = this.GetUniquePaths_DP_Memoization_Lazy(3);
            Assert.AreEqual(p, p1);
            var p2 = this.GetUniquePaths(3);
            Assert.AreEqual(p1, p2.Length);
            foreach (var path in p2)
            {
                Debug.WriteLine("===================================================================");
                foreach (Tuple<int, int> t in path)
                {
                    Debug.Write(string.Format("({0}, {1}), ", t.Item1, t.Item2));
                }
            }
            p = this.GetNumberOfUniquePaths(4);
            Assert.AreEqual(p, 20);
            p1 = this.GetUniquePaths_DP_Memoization_Lazy(4);
            Assert.AreEqual(p, p1);
            p2 = this.GetUniquePaths(4);
            Assert.AreEqual(p1, p2.Length);
            foreach (var path in p2)
            {
                Debug.WriteLine("===================================================================");
                foreach (Tuple<int, int> t in path)
                {
                    Debug.Write(string.Format("({0}, {1}), ", t.Item1, t.Item2));
                }
            }
        }
   import java.util.Arraylist;

   public class PrintPath
   {
    static ArrayList<String> paths = new ArrayList<String>(); 

    public static long getUnique(int m, int n, int i, int j, String pathlist)
    {

        pathlist += ("(" + i + ", " + (j) + ") => ");

        if(m == i && n == j)
        {       
            paths.add(pathlist); 
        }

        if( i > m || j > n)
        {
            return 0;               
        }

        return getUnique(m, n, i+1, j, pathlist)+getUnique(m, n, i, j+1, pathlist); 

    }

    public static void printPaths()
    {
        int count = 1;
        System.out.println("There are "+paths.size() + " unique paths: \n");

        for (int i = paths.size()-1; i>=0; i--)
        {

         System.out.println( "path " + count + ":   " + paths.get(i));
         count++;
        }

    }

    public static void main(String args[])
    {
        final int start_Point = 1;
        int grid_Height = 2; 
        int grid_Width = 2; 

        getUnique(grid_Height, grid_Width, start_Point, start_Point, "");
        printPaths(); 

    }

}
//first make a function to create the board as an array of arrays
var makeBoard = function(n) {
  var board = [];
  for (var i = 0; i < n; i++) {
    board.push([]);
    for (var j = 0; j < n; j++) {
      board[i].push(false);
    }
  }
  board.togglePiece = function(i, j) {
    this[i][j] = !this[i][j];
  }
  board.hasBeenVisited = function(i, j) {
    return !!this[i][j];
  }
  board.exists = function(i, j) {
    return i < n && i > -1 && j < n && j > -1;
  }
  board.viablePosition = function(i, j) {
    return board.exists(i, j) && !board.hasBeenVisited(i,j);
  }
  return board;
};


var robotPaths = function(n) {
  var numPaths = 0;
  //call our recursive function (defined below) with a blank board of nxn, with the starting position as (0, 0)
  traversePaths(makeBoard(n), 0, 0);

  //define the recursive function we'll use
  function traversePaths(board, i, j) {
    //BASE CASE: if reached (n - 1, n - 1), count as solution and stop doing work
    if (i === (n - 1) && j === (n - 1)) {
      numPaths++;
      return;
    }
    //mark the current position as having been visited. Doing this after the check for BASE CASE because you don't want to turn the target position (i.e. when you've found a solution) to true or else future paths will see it as an unviable position
    board.togglePiece(i, j);

    //RECURSIVE CASE: if next point is a viable position, go there and make the same decision

    //go right if possible
    if (board.viablePosition(i, j + 1)) {
      traversePaths(board, i, j + 1);
    }

    //go left if possible
    if (board.viablePosition(i, j - 1)) {
      traversePaths(board, i, j - 1);
    }

    //go down if possible
    if (board.viablePosition(i + 1, j)) {
      traversePaths(board, i + 1, j);
    }

    //go up if possible
    if (board.viablePosition(i - 1, j)) {
      traversePaths(board, i - 1, j);
    }

    //reset the board back to the way you found it after you've gone forward so that other paths can see it as a viable position for their routes
    board.togglePiece(i, j);
  }
  return numPaths;
};
var robotPaths = function(n, board, i, j) {
    board = board || makeBoard(n),
    i = i || 0,
    j = j || 0;

    // If current cell has been visited on this path or doesn't exist, can't go there, so do nothing (no need to return since there are no more recursive calls below this)
    if (!board.viablePosition(i, j)) return 0;
    // If reached the end, add to numPaths and stop recursing
    if (i === (n - 1) && j === (n - 1)) return 1;
    // Mark current cell as having been visited for this path
    board.togglePiece(i, j);
    // Check each of the four possible directions
    var numPaths = robotPaths(n, board, i + 1, j) + robotPaths(n, board, i - 1, j) + robotPaths(n, board, i, j + 1) + robotPaths(n, board, i, j - 1);
    // Reset current cell so other paths can go there (since board is a pointer to an array that every path is accessing)
    board.togglePiece(i, j);
    return numPaths;
}
robotPaths(5); //returns 8512
// a is a matrix with 0s and -1s
// n, m are the dimensions
// M is 10^9-7 incase you have a large matrix

if (a[0][0] == 0) a[0][0] = 1;
for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        if (a[i][j] == -1) continue;
        if (i > 0) a[i][j] = (a[i][j] + max(a[i-1][j], 0LL)) % M;
        if (j > 0) a[i][j] = (a[i][j] + max(a[i][j-1], 0LL)) % M;
    }
}

// answer at lower right corner
cout << a[n-1][m-1];
public class paths_in_matrix {

    /**
     * @param args
     */
    static int n=5;
    private boolean[][] board=new boolean[n][n];
    int numPaths=0;
    paths_in_matrix(){
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                board[i][j]=false;
            }
        }
    }
    private void togglePiece(int i,int j){
        this.board[i][j]=!this.board[i][j];
    }
    private boolean hasBeenVisited(int i,int j){
        return this.board[i][j];
    }
    private boolean exists(int i,int j){
        return i < n && i > -1 && j < n && j > -1;
    }
    private boolean viablePosition(int i,int j){
        return exists(i, j) && !hasBeenVisited(i,j);
    }
    private void traversePaths(int i,int j){
        //BASE CASE: if reached (n - 1, n - 1), count as path and stop. 
        if (i == (n - 1) && j == (n - 1)) {
          this.numPaths++;
          return;
        }
        this.togglePiece(i, j);
        //RECURSIVE CASE: if next point is a viable position, go there and make the same decision

        //go right if possible
        if (this.viablePosition(i, j + 1)) {
          traversePaths(i, j + 1);
        }
      //go left if possible
        if (this.viablePosition(i, j - 1)) {
          traversePaths( i, j - 1);
        }

        //go down if possible
        if (this.viablePosition(i + 1, j)) {
          traversePaths( i + 1, j);
        }

        //go up if possible
        if (this.viablePosition(i - 1, j)) {
          traversePaths(i - 1, j);
        }

        //reset the board back to the way you found it after you've gone forward so that other paths can see it as a viable position for their routes
        this.togglePiece(i, j);

    }
    private int robotPaths(){

        traversePaths(0,0);
        return this.numPaths;
    }
    public static void main(String[] args) {
        paths_in_matrix mat=new paths_in_matrix();
        System.out.println(mat.robotPaths());
    }

}