题目
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/unique-paths-ii
方法1:动态规划
这道题是62题的基础上变难一点,没做过62题,可以先去做62
【LeetCode-中等】62. 不同路径(详解)
思路:
每个方格的走法数只能由:其上方方格的走法数 + 其左方方格的走法数
如果遇到左边 或 上边有障碍物或者是边界,那就不要加它的数值
所以想到动态规划
动态规划 三步走
动态规划,就是利用历史记录,来避免我们的重复计算。而这些历史记录,我们得需要一些变量来保存,一般是用一维数组或者二维数组来保存。下面我们先来讲下做动态规划题很重要的三个步骤,
1.定义dp数组
我们会用一个数组,来保存历史数组,假设用一维数组 dp[] 吧。这个时候有一个非常重要的点,就是规定你这个数组元素的含义,例如你的 dp[i] 是代表什么意思?
2.找出递推关系式
动态规划类似于高中数学的数学归纳法,当我们要计算 dp[n] 时,是可以利用 dp[n-1],dp[n-2]…..dp[1],来推出 dp[n] 的,也就是可以利用历史数据来推出新的元素值,所以我们要找出数组元素之间的关系式,例如 dp[n] = dp[n-1] + dp[n-2],这个就是他们的关系式了。
3.找出初始值
找出了递推公式,我们还需要初始值,因为递推公式就是靠前面的值推出后面的值,但总得有个头吧,这个头就是初始值。
提示
代码如何排错?将dp数组全部输出看看
对动态规划完全不会的同学可以先去做下面两道动态规划入门题
【LeetCode-简单】509. 斐波那契数(详解)
【LeetCode-简单】70. 爬楼梯(详解)
1. dp[i]:代表着当前方格的走法数,这里直接在原数组上修改,不需要额外的dp数组
2.递推关系式: 每个方格的走法数只能由:其上方不是障碍物和边界的方格的走法数 + 其左方不是障碍物和边界方格的走法数
3.初始化:dp[0][0] = 1
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
if (obstacleGrid[m-1][n-1] == 1 || obstacleGrid[0][0] == 1)return 0;//说你跟障碍物在终点 或者 障碍物在起点
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
//初始化
if (i == 0 && j == 0) {
obstacleGrid[i][j] = 1;
continue;
}
if (obstacleGrid[i][j] == 1){//说明此处是障碍物
obstacleGrid[i][j] = 0;//将障碍物出的值变为0,方便其他方格进行观察
continue;
}
//如果左边不越界,且左边不是障碍物 就加上左边
if (j-1 >= 0 && obstacleGrid[i][j-1] != -1){
obstacleGrid[i][j] =obstacleGrid[i][j] + obstacleGrid[i][j-1];
}
//如果上边不越界,且上边不是障碍物 就加上上边
if (i-1 >= 0 && obstacleGrid[i-1][j] != -1){
obstacleGrid[i][j] =obstacleGrid[i][j] + obstacleGrid[i-1][j];
}
}
}
return obstacleGrid[m-1][n-1];
}
}
动态规划真好用