NC34 求路径

题目思路:这道题目其实很一道很经典的动态规划题目,题目意思很好理解,就是找从起点到终点的所有可行的路径。

约束的两个条件:

  • 机器人每次只能往右或者往下走
  • 机器人不能越界

我们看到这张图就明白一切:

34

方法一:经典使用dp数组

有了上面的两个条件,我们就可以解决这个题目了。

我们定义一个二维dp数组,dp[i] [j] 表示从起点到我当前位置(i行j列)有多少条可行的路径,因为我们从约束条件中可以知道,机器人每次只能往右或者往下走,则我们当前点必定是从上面或者左边走过来的(除边界外)。

当然,如果在地图的最上面或者最左边的话,最上面的点只能是从左边走到的,最左边的点只能是从上面走到的。

则我们可以定义状态方程:

当 i > 1 && j > 1 : dp[i] [j] = dp[i] [j-1] + dp[i-1] [j]

当 i = 0:dp[0] [j] = dp[0] [j-1]

当 j = 0:dp[i] [0] = dp[i-1] [0]

所以我们可以写出代码:

public int uniquePaths (int m, int n) {
        // 定义dp数组
        int[][] dp = new int[m][n];

        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                // 当 i = 0:dp[0][j] = dp[0][j-1]
                if(i == 0){
                    dp[i][j] = 1; // 都是1是因为dp[0][j] = dp[0][j-1],所以干脆全部赋值为1
                    continue;
                }
                // 当 j = 0:dp[i][0] = dp[i-1][0]
                if(j == 0){
                    dp[i][j] = 1;
                    continue;
                }
                // 当 i > 1 && j > 1 :  dp[i][j] = dp[i][j-1] + dp[i-1][j]
                dp[i][j] = dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1]; // 返回到达终点的所有可行路径
    }

方法二:递归

上面的方法是用一个dp数组来存储的,但是代码量是不是有点多,其实我们也可以用递归来实现动态规划,具体看下面的代码:

public int uniquePaths (int m, int n) {
        // 起点(1,1) 这里为什么是(1,1)呢?其实是一样的,我们上面的方法定义了(0,0)为起点,那么终点就为(m-1,n-1)
        // 这里起点为(1,1)那么终点就为 (m,n)
        if(m == 1 || n == 1)
            return 1;
        // 终点(m,n)
        return uniquePaths(m,n-1)+uniquePaths(m-1,n);
    }

我们看到上面的代码,是不是也很容易理解,主要是代码量非常的少,并且代码的可读性也提升了。

我们可以看到 uniquePaths(m,n-1)+uniquePaths(m-1,n)符合了我们的状态方程。

复杂度分析:

时间复杂度O(n2):计算的时候,双重循环

空间复杂度O(n2):二维数组的空间。