算法修炼Day39|62.不同路径 ● 63. 不同路径 II

70 阅读3分钟

LeetCode:62. 不同路径 - 力扣(LeetCode)

1.思路

当前位置的路径数是上头上一个和左侧一个的和,所以可以一点点推导,想到动规。

动规五部曲:

确定dp[i][j]数组定义:到达(i, j)处有 dp[i][j] 种路径 或 到达第 i 行,第 j 列有 dp[i][j] 种路径;

确定递推公式:dp[i][j] = dp[i - 1][j] + dp[i][j - 1];

初始化:

行初始化:每列的首位数初始化为 1,也即dp[i][0];

列初始化:每行的首位数初始化为 1 ,也即dp[0][j];

确定遍历顺序:先行后列,和dp数组的定义有关

打印dp数组:好懒。。

小问题:dp[][]数组的大小边界怎么明确?遍历顺序怎么更清晰?做题的框架感得更清晰

2.代码实现
class Solution {
    public int uniquePaths(int m, int n) {
        // 到达(i, j)处有 dp[i][j] 种路径 或 到达第 i 行,第 j 列有 dp[i][j] 种路径
        int[][] dp = new int[m][n];
        // 初始化
        // 列初始化:每行的首位数初始化为 1 
        for (int i = 0; i < m; i++) {
            dp[i][0] = 1;
        }
        // 行初始化:每列的首位数初始化为 1
        for (int i = 0; i < n; i++) {
            dp[0][i] = 1;
        }
        // 递推公式 dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
        // 遍历顺序:先行后列(和dp数组的声明有关)
        for (int i = 1; i < m; i++) { // 行
            for (int j = 1; j < n; j++) { // 列
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        return dp[m - 1][n - 1];
    }
}
3.复杂度分析

时间复杂度:O(n * m).

空间复杂度:O(n).

LeetCode:63. 不同路径 II - 力扣(LeetCode)

1.思路

在上一题的基础上,增加了中介障碍,在动规过程都要考虑这个障碍,有障碍和无障碍的赋值,有障碍直接赋值为0,表示到不了,无障碍就是头上一个和左侧一个值的和。 动规五部曲之四步:

①确定dp[i][j]数组的含义,到达(i, j)位置所具有的路径数。

②确定动规公式:dp[i][j] = (obstacle[i][j] == 0) ? dp[i - 1][j] + dp[i][j - 1] : 0

③初始化:初始化首行和首列,没有障碍的地方全部初始化为1,有障碍的默认为0.

④单层动规逻辑:先行后列,和dp[][]数组定义有关

⑤(没有)打印dp[][]数组

2.代码实现
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        // dp数组
        int[][] dp = new int[m][n]; // 大小怎么定?
        // 首尾节点为障碍的边界值排除
        if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1) {
            return 0;
        }
        // 初始化
        // 列初始化:每行的首个位置没有障碍时均为 1 
        for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) {
            dp[i][0] = 1;
        }
        // 行初始化:每列的首个位置没有障碍时均为 1
        for (int i = 0; i < n && obstacleGrid[0][i] == 0; i++) {
            dp[0][i] = 1;
        } 
        // 动规遍历顺序:先行后列
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = (obstacleGrid[i][j] == 0) ? dp[i -1][j] + dp[i][j - 1] : 0;
            }
        }
        return dp[m - 1][n - 1];
    }
}
3.复杂度分析

时间复杂度:O(n * m).

空间复杂度:O(n).