62.不同路径63. 不同路径 II

62.不同路径

62.不同路径

// 动态规划清晰步骤: 1. 定义dp数组 2. 初始化 3. 循环填充 4. 返回结果
class Solution {
    // 也是一个从起点到终点的问题, 1) dp[i][j],表示i,j格子的不同路径数, 2) dp[0][0] = 1 dp[0][1] =1 dp[1][0] = 1 3) dp[i][j] = dp[i-1][j] + dp[i][j-1]; 4) 左上到右下
    public int uniquePaths(int m, int n) {
        // 1. 定义dp数组
        int[][] dp = new int[m][n];
        // 2. 初始化
        for (int i = 0; i < m; i++) dp[i][0] = 1;
        for (int j = 0; j < n; j++) dp[0][j] = 1;
        // 3. 循环填充
        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];
            }
        }
        // 4. 返回结果
        return dp[m - 1][n - 1];
    }
}

// 动态规划写法2: 内部解决初始化问题
class Solution2 {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (i == 0 && j != 0) {
                    dp[i][j] = dp[i][j - 1];
                } else if (i != 0 && j == 0) {
                    dp[i][j] = dp[i - 1][j];
                } else if (i == 0 && j == 0) {
                    dp[i][j] = 1;
                } else {
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
        }
        return dp[m - 1][n - 1];
    }
}

// 深度优先搜索DFS: 可以遍历二叉树, 可以从头到尾遍历每一条路径(更彻底), 但是本题只需要知道多少条路径。所以是充分不必要条件。
// 所有寻路的过程可以连接成一个二叉树, 每个叶子节点说明一条路径
class Solution3 {
    private int postOrder(int i, int j, int m, int n) {
        //越界, 不能构成一种可能, 但是在这里也会发现即使不构成可能也会被算法遍历这种可能(产生过搜索),时间复杂度高
        // Leetcode中会超时, 可以进行剪枝优化
        if (i >= m || j >= n) return 0;
        // 符合条件的一种可能
        if (i == m - 1 && j == n - 1) return 1;
        int left = postOrder(i + 1, j, m, n);
        int right = postOrder(i, j + 1, m, n);
        return left + right;
    }

    public int uniquePaths(int m, int n) {
        return postOrder(0, 0, m, n);
    }
}
// 剪枝, LeetCode中还是会超时
class Solution4 {
    private int postOrder(int i, int j, int m, int n) {
        // 符合条件的一种可能
        if (i == m - 1 && j == n - 1) return 1;
        int left = 0;
        int right = 0;
        if (i + 1 < m) left = postOrder(i + 1, j, m, n);
        if (j + 1 < n) right = postOrder(i, j + 1, m, n);
        return left + right;
    }

    public int uniquePaths(int m, int n) {
        return postOrder(0, 0, m, n);
    }
}
// 排列组合思路:我们需要移动 (m - 1) + (n - 1)次,其中有 m−1 次向下移动,n−1 次向右移动。因此路径的总数,就等于从 m+n−2 次移动中选择 m−1 次向下移动的方案数,即组合数:
// 计算是全排列然后去重

63. 不同路径 II

63. 不同路径 II

// 本题很简单, 只需要将62题, dp数组对于障碍物的位置改为0即可: 1. 定义dp数组 2. 初始化 3. 循环填充 4. 返回结果
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        // 1. 定义dp数组
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        int[][] dp = new int[m][n];
        // 2. 初始化
        if (obstacleGrid[0][0] == 1) return 0; // 打补丁测试用例
        dp[0][0] = 1;
        for (int i = 1; i < m; i++) if (obstacleGrid[i][0] == 0) dp[i][0] = dp[i - 1][0];
        for (int j = 1; j < n; j++) if (obstacleGrid[0][j] == 0) dp[0][j] = dp[0][j - 1];
        // 3. 循环填充
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (obstacleGrid[i][j] == 0) dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                else dp[i][j] = 0;
            }
        }
        // 4. 返回结果
        return dp[m - 1][n - 1];
    }
}
posted @ 2022-03-06 17:10  -Rocky-  阅读(30)  评论(0编辑  收藏  举报