1.题目链接:
2.题目描述:
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
示例 1:
输入:
obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:
2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
a. 向右 -> 向右 -> 向下 -> 向下
b. 向下 -> 向下 -> 向右 -> 向右
3. 解法(动态规划):
算法思路:
本题为不同路径的变型,只不过有些地方有「障碍物」,只要在「状态转移」上稍加修改就可解决。
1. 状态表示:
对于这种「路径类」的问题,我们的状态表示一般有两种形式:
i. | 从 [i, j] 位置出发,巴拉巴拉; |
ii. 从起始位置出发,到达 [i, j] 位置,巴拉巴拉。这里选择第二种定义状态表示的方式:
dp[i][j] 表示:走到 [i, j] 位置处,一共有多少种方式。
2. 状态转移:
简单分析一下。如果 dp[i][j] 表示到达 [i, j] 位置的方法数,那么到达 [i, j] 位置之前的一小步,有两种情况:
i. | 从 [i, j] 位置的上方([i - 1, j] 的位置)向下走一步,转移到 [i, j] 位置; |
ii. 从 [i, j] 位置的左方([i, j - 1] 的位置)向右走一步,转移到 [i, j] 位置。
但是,[i - 1, j] 与 [i, j - 1] 位置都是可能有障碍的,此时从上面或者左边是不可能
到达 [i, j] 位置的,也就是说,此时的方法数应该是 0。
由此我们可以得出一个结论,只要这个位置上「有障碍物」,那么我们就不需要计算这个位置上的
值,直接让它等于 0 即可。
3. 初始化:
可以在最前面加上一个「辅助结点」,帮助我们初始化。使用这种技巧要注意两个点:
i. 辅助结点里面的值要「保证后续填表是正确的」;
ii. 「下标的映射关系」。
在本题中,添加一行,并且添加一列后,只需将 dp[1][0] 的位置初始化为 1 即可。
4. 填表顺序:
根据「状态转移」的推导,填表的顺序就是「从上往下」填每一行,每一行「从左往右」。
5. 返回值:
根据「状态表示」,我们要返回的结果是 dp[m][n] 。
Java算法代码:
class Solution {
public int uniquePathsWithObstacles(int[][] ob) {
//1.创建dp表
//2.初始化
// 3.填表
// 4.返回
int m = ob.length, n = ob[0].length;
int [][] dp = new int[m+1][n+1];
dp[1][0] = 1;
for(int i = 1; i <= m; i++){
for(int j = 1; j <=n; j++){
if(ob[i - 1][j - 1] == 0){
dp[i][j] = dp[i -1][j] + dp[i][j-1];
}
}
}
return dp[m][n];
}
}
运行结果:
动态规划: