导语
leetcode刷题笔记记录,本篇博客是动态规划部分的第二期,主要记录题目包括:
- 62.不同路径
-
- 不同路径 II
Leetcode 62.不同路径
题目描述
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。问总共有多少条不同的路径?
示例 1:
输入: m = 3, n = 7
输出: 28
示例 2:
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下
提示:
1 <= m, n <= 100- 题目数据保证答案小于等于
2 * 109
解法
使用动规五部曲:
- dp数组含义:dp[i][j]表示从(0,0)到(i,j)有多少种不同的路径;
- 递推公式:
- 初始化:应该将第一行和第一列初始化为1
- 遍历顺序:由于递归公式中需要上方和左方的值,所以应该是从上往下,从左往右;
- 打印dp数组;
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
# 初始化一个 m x n 的二维数组,全部填充为0
# 这个数组dp[i][j]表示从起始点到(i, j)位置的不同路径数量
dp = [[0] * n for i in range(m)]
# 设置起点到第一列的任意位置都只有一条路径(机器人只能一直向下走)
for i in range(m):
dp[i][0] = 1
# 设置起点到第一行的任意位置都只有一条路径(机器人只能一直向右走)
for j in range(n):
dp[0][j] = 1
# 使用动态规划填充数组
# 对于位置(i, j),机器人只有两种方式到达:从(i-1, j) 或者 从(i, j-1)
# 所以,dp[i][j] = dp[i-1][j] + dp[i][j-1]
for i in range(1, m):
for j in range(1, n):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
# 返回起始点到(m-1, n-1)位置的路径数量,即整个网格的右下角
return dp[m-1][n-1]
易错点
遍历时,i,j都是从1开始的,而不是0,请注意!
Leetcode 63. 不同路径 II
题目描述
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?网格中的障碍物和空位置分别用 1 和 0 来表示。
示例 1:
输入: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出: 2
解释: 3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
示例 2:
输入: obstacleGrid = [[0,1],[0,0]]
输出: 1
提示:
m == obstacleGrid.lengthn == obstacleGrid[i].length1 <= m, n <= 100obstacleGrid[i][j]为0或1
解法
相比于上一题,这一题增加了障碍,因此,我们的递推公式和数组初始化部分需要进行修改,具体如下:
- 递归公式的更新仅当该位置没有障碍时才进行更新;
- dp数组初始化时,遇到障碍后的地方初始化为0,而不是1;
修改后代码如下:
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
# 获取网格的行数m和列数n
m, n = len(obstacleGrid), len(obstacleGrid[0])
# 初始化一个 m x n 的二维数组,全部填充为0
# 这个数组dp[i][j]表示从起始点到(i, j)位置的不同路径数量
dp = [[0] * n for i in range(m)]
# 初始化第一列的路径数量
# 如果一个位置上有障碍物,则这个位置及其之后的所有位置都不可达,因此路径数量为0
for i in range(m):
if obstacleGrid[i][0] == 1:
break
dp[i][0] = 1
# 初始化第一行的路径数量
# 如果一个位置上有障碍物,则这个位置及其之后的所有位置都不可达,因此路径数量为0
for j in range(n):
if obstacleGrid[0][j] == 1:
break
dp[0][j] = 1
# 使用动态规划填充数组
# 对于没有障碍物的位置(i, j),机器人只有两种方式到达:从(i-1, j) 或者 从(i, j-1)
# 所以,dp[i][j] = dp[i-1][j] + dp[i][j-1]
# 如果位置(i, j)上有障碍物,则 dp[i][j] 默认为0
for i in range(1, m):
for j in range(1, n):
if obstacleGrid[i][j] == 0:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
# 返回起始点到(m-1, n-1)位置的路径数量,即整个网格的右下角
return dp[m-1][n-1]