不同路径 II(力扣LeetCode)动态规划

不同路径 II

题目描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。

示例 1:

不同路径 II(力扣LeetCode)动态规划_第1张图片
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:

  • 向右 -> 向右 -> 向下 -> 向下
  • 向下 -> 向下 -> 向右 -> 向右

示例 2:

不同路径 II(力扣LeetCode)动态规划_第2张图片
输入:obstacleGrid = [[0,1],[0,0]]
输出:1

提示:

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

动规五部曲:

  1. 确定dp数组(dp table)以及下标的含义
    dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。
  2. 确定递推公式
    递推公式和62.不同路径⼀样,dp[i][j] = dp[i - 1][j] + dp[i][j - 1]。
    但这⾥需要注意⼀点,因为有了障碍,(i, j)如果就是障碍的话应该就保持初始状态(初始状态为0)。
    所以代码为:
if (obstacleGrid[i][j] == 0) { // 当(i, j)没有障碍的时候,再推导dp[i][j]
	dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
  1. dp数组如何初始化
    在不同路径不同路径中我们给出如下的初始化:
vector<vector<int>> dp(m, vector<int>(n, 0)); // 初始值为0
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;

因为从(0, 0)的位置到(i, 0)的路径只有⼀条,所以dp[i][0]⼀定为1,dp[0][j]也同理。
但如果(i, 0) 这条边有了障碍之后,障碍之后(包括障碍)都是⾛不到的位置了,所以障碍之后的dp[i][0]应该还是
初始值0。
如图:
不同路径 II(力扣LeetCode)动态规划_第3张图片
下标(0, j)的初始化情况同理。
所以本题初始化代码为:

vector<vector<int>> dp(m, vector<int>(n, 0));
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;

注意代码⾥for循环的终⽌条件,⼀旦遇到obstacleGrid[i][0] == 1的情况就停⽌dp[i][0]的赋值1的操作,dp[0][j]同理
4. 确定遍历顺序
从递归公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 中可以看出,⼀定是从左到右⼀层⼀层遍历,这样保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]⼀定是有数值。
代码如下:

for (int i = 1; i < m; i++) {
	for (int j = 1; j < n; j++) {
		if (obstacleGrid[i][j] == 1) continue;
		dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
	}
}
  1. 举例推导dp数组
    拿示例1来举例如题:
    不同路径 II(力扣LeetCode)动态规划_第4张图片
    对应的dp table 如图:
    不同路径 II(力扣LeetCode)动态规划_第5张图片
    如果这个图看不懂,建议再理解⼀下递归公式,然后照着⽂章中说的遍历顺序,⾃⼰推导⼀下!

力扣提交代码

c++

class Solution {
public:
	int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
		int m = obstacleGrid.size();
		int n = obstacleGrid[0].size();
		if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1) //如果在起点或终点出现了障碍,直接返回0
			return 0;
		vector<vector<int>> dp(m, vector<int>(n, 0));
		for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
		for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
		for (int i = 1; i < m; i++) {
			for (int j = 1; j < n; j++) {
				if (obstacleGrid[i][j] == 1) continue;
				dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
			}
		}
		return dp[m - 1][n - 1];
	}
};

c语言

int uniquePathsWithObstacles(int** obstacleGrid, int obstacleGridSize, int* obstacleGridColSize) 
{
    int n=obstacleGridSize;// 定义障碍物网格行数
    int m=obstacleGridColSize[0];// 定义障碍物网格列数
    //如果在起点或终点出现了障碍,直接返回0
    if(obstacleGrid[0][0]==1||obstacleGrid[n-1][m-1]==1)    return 0;

    int i,j;
    int dp[110][110]={0};//所有元素先初始化为0
    //初始化dp数组
    for(i=0;i<n&&obstacleGrid[i][0]==0;i++) dp[i][0]=1;//第一行如果遇到障碍物,则后面为0
    for(j=0;j<m&&obstacleGrid[0][j]==0;j++) dp[0][j]=1;//第一列如果遇到障碍物,则后面为0

    for(i=1;i<n;i++)
    {
        for(j=1;j<m;j++)
        {
            if(obstacleGrid[i][j]==1)   continue;//遇到障碍物就跳过继续
            dp[i][j]=dp[i-1][j]+dp[i][j-1];
        }
    }
    return dp[n-1][m-1];
}

你可能感兴趣的:(leetcode,leetcode,动态规划,算法,c++,c语言)