力扣刷题笔记《动态规划篇》→ 63. 不同路径 II

277 阅读2分钟

这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战

题目

一个机器人位于一个 m×nm \times n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

63. 不同路径 II.png

网格中的障碍物和空位置分别用 1 和 0 来表示。

示例

示例1.png

输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右

示例2.png

输入: obstacleGrid = [[0,1],[0,0]]
输出: 1

提示

  • m == obstacleGrid.length
  • n == obstacleGrid[i].length
  • 1 <= m, n <= 100
  • obstacleGrid[i][j] 为 0 或 1

解题思路

该题整体上的解题思路跟《62. 不同路径》一样,都是通过前置方向来累加结果得出最终值,不同的地方在于该题的路径中会有障碍物的存在。

一旦机器人走到了障碍物的位置,将不能继续向下或向右移动,所以这里需要添加多一个判断操作。

63. 不同路径 II.jpg

代码实现

方法一:动态规划

class Solution {
    public int uniquePathsWithObstacles(int[][] o) {
        int m = o.length, n = o[0].length;
        // 边界处理
        if(o[0][0] == 1 || o[m - 1][n - 1] == 1){
            return 0;
        }

        // 初始化首行首列
        int[][] dp = new int[m][n];
        dp[0][0] = 1;
        for(int i = 1; i < m && o[i][0] == 0; ++i){
            dp[i][0] = 1;
        }
        for(int i = 1; i < n && o[0][i] == 0; ++i){
            dp[0][i] = 1;
        }

        // 累加前面路径数量
        for(int i = 1; i < m; ++i){
            for(int j = 1; j < n; ++j){
                if(o[i][j] == 1){
                    continue;
                }
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        // 返回结果
        return dp[m - 1][n - 1];
    }
}

复杂度分析

  • 时间复杂度:O(MN)O(MN)
  • 空间复杂度:O(MN)O(MN)

方法二:动态规划优化

class Solution {
    public int uniquePathsWithObstacles(int[][] o) {
        int m = o.length, n = o[0].length;
        // 边界判断
        if(o[0][0] == 1 || o[m - 1][n - 1] == 1){
            return 0;
        }
        
        // 初始化
        int[] dp = new int[n];
        dp[0] = 1;

        // 状态转移
        for(int i = 0; i < m; ++i){
            for(int j = 0; j < n; ++j){
                // 当前位置为障碍物时,表示没有后续路径,将当前位置赋值为0
                if(o[i][j] == 1){
                    dp[j] = 0;
                    continue;
                }
                
                // o[j][0]的来源永远只有o[j - 1][0],所以这里只需要判断后面的部分
                // dp[j]相当于dp[i - 1][j],还未更新,取上边路径
                // dp[j - 1]相当于dp[i][j - 1],已更新,取左边路径
                if(j > 0){
                    dp[j] += dp[j - 1];
                }
            }
        }

        // 返回结果
        return dp[n - 1];
    }
}

复杂度分析

  • 时间复杂度:O(MN)O(MN)
  • 空间复杂度:O(N)O(N)

最后

文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!

如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!

题目出处: leetcode-cn.com/problems/un…