题目描述
题目链接:63.不同路径 ||
本题为不同路径的变型,只不过有些地⽅有障碍物,只要在状态转移上稍加修改就可解决。
算法原理
1.状态表示
对于这种路径类的问题,我们的状态表示⼀般有两种形式:
- 从 [i, j] 位置出发…
- 从起始位置出发,到达 [i, j] 位置…
这⾥选择第⼆种定义状态表示的⽅式:
dp[i][j] 表示:⾛到 [i, j] 位置处,⼀共有多少种⽅式。
2.状态转移方程
根据最近的一步划分问题。简单分析⼀下。如果 dp[i][j] 表示到达 [i, j] 位置的⽅法数,那么到达 [i, j] 位置之前的⼀⼩步,有两种情况:
- 从 [i, j] 位置的上⽅( [i - 1, j] 的位置)向下⾛⼀步,转移到 [i, j] 位置;
- 从 [i, j] 位置的左⽅( [i, j - 1] 的位置)向右⾛⼀步,转移到 [i, j] 位置。
但是, [i - 1, j] 与 [i, j - 1] 位置都是可能有障碍的,此时从上⾯或者左边是不可能到达 [i, j] 位置的,也就是说,此时的⽅法数应该是 0。 由此我们可以得出⼀个结论,只要这个位置上有障碍物,那么我们就不需要计算这个位置上的
值,直接让它等于 0 即可。
3.初始化
可以在最前⾯加上⼀个辅助结点,帮助我们初始化。使⽤这种技巧要注意两个点:
- 辅助结点⾥⾯的值要保证后续填表是正确的;
- 下标的映射关系。
在本题中,添加⼀⾏,并且添加⼀列后,只需将 dp[1][0] 或者 dp[0][1] 的位置初始化为 1 即可。
4.填表顺序
根据状态转移的推导,填表的顺序就是从上往下填每一行,每一行从左往右。
5.返回值
根据状态表示,我们要返回的结果是 dp[m][n] 。
代码实现
C++
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
//1.创建一个dp表
int m = obstacleGrid.size(),n = obstacleGrid[0].size();
vector<vector<int>> dp(m + 1,vector<int>(n + 1));
//2.初始化
dp[0][1] = 1;//也可以写dp[1][0] = 1;
//3.填表
for(int i = 1;i <= m;++i) {
for(int j = 1;j <= n;++j) {
if(obstacleGrid[i - 1][j - 1] == 0)//dp表对应到ob表注意下标
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
//4.返回值
return 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];
}
}