题目:62. 不同路径
链接:https://leetcode-cn.com/problems/unique-paths/
解题思路
(1)深度优先搜索
这道题⽬最直观的想法就是⽤图论⾥的深搜,来枚举出来有多少种路径。
注意题⽬中说机器⼈每次只能向下或者向右移动⼀步,那么其实机器⼈⾛过的路径可以抽象为⼀颗⼆叉树,⽽叶⼦节点就是终点!
(2)动态规划
1. 确定dp数组以及下标的含义
dp[i][j] :表示从(0,0)出发,到(i, j)有dp[i][j]条不同的路径。
2. 确定递推公式
想要求dp[i][j],只能有两个方向来推导出来,即dp[i-1][j] 和 dp[i][j-1]。
此时在回顾⼀下 dp[i-1][j] 表示啥,是从(0, 0)的位置到(i-1, j)有几条路径,dp[i][j-1]同理。
那么很自然,dp[i][j] = dp[i-1][j] + dp[i][j-1],因为dp[i][j]只有这两个方向过来。
3. dp数组的初始化
首先dp[i][0]⼀定都是1,因为从(0, 0)的位置到(i, 0)的路径只有一条,那么dp[0][j]也同理。
初始化代码:
# 初始化dp数组
for i in range(m): dp[i][0] = 1
for j in range(n): dp[0][j] = 1
4. 确定遍历顺序
这里要看一下递归公式dp[i][j] = dp[i-1][j] + dp[i][j-1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。
这样就可以保证推导dp[i][j]的时候,dp[i-1][j] 和 dp[i][j-1]⼀定是有数值的。
代码实现
(1)深度优先搜索
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
'''深度优先搜索'''
'''时间复杂度为O(2^(m + n - 1) - 1)'''
'''时间超时'''
def dfs(i,j,m,n):
if i>m or j>n: return 0
if i==m and j==n: return 1
return dfs(i+1,j,m,n) + dfs(i,j+1,m,n)
return dfs(1,1,m,n)
(2)动态规划
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
'''动态规划'''
# 定义dp数组m行,n列
dp = [[0]*n for _ in range(m)]
# 初始化dp数组
for i in range(m): dp[i][0] = 1
for j in range(n): dp[0][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]
return dp[-1][-1]
解题思路来源于代码随想录
题目:63. 不同路径 II
链接:https://leetcode-cn.com/problems/unique-paths-ii/
解题思路
1. 确定dp数组以及下标的含义
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] == 1: continue
dp[i][j] = dp[i-1][j] + dp[i][j-1]
3. dp数组如何初始化
如果(i, 0) 这条边有了障碍之后,障碍之后(包括障碍)都是走不到的位置了,所以障碍之后的dp[i][0]应该还是初始值0。
# 初始化dp数组
# 第一行
for i in range(1,n):
if obstacleGrid[0][i] != 1:
dp[0][i] = dp[0][i-1]
# 第一列
for i in range(1, m):
if obstacleGrid[i][0] != 1:
dp[i][0] = dp[i-1][0]
4. 确定遍历顺序
从递归公式dp[i][j] = dp[i-1][j] + dp[i][j-1] 中可以看出,一定是从左到右一层一层遍历,这样保证推导 dp[i][j]的时候,dp[i-1][j] 和 dp[i][j-1]一定是有数值。
代码实现
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
# 定义dp数组
m = len(obstacleGrid)
n = len(obstacleGrid[0])
dp = [[0]*n for _ in range(m)]
dp[0][0] = 1 if obstacleGrid[0][0] != 1 else 0
if dp[0][0] == 0: return 0 # 如果第一个格子就是障碍,return 0
# 初始化dp数组
# 第一行
for i in range(1,n):
if obstacleGrid[0][i] != 1:
dp[0][i] = dp[0][i-1]
# 第一列
for i in range(1, m):
if obstacleGrid[i][0] != 1:
dp[i][0] = dp[i-1][0]
for i in range(1,m):
for j in range(1, n):
if obstacleGrid[i][j] == 1: continue
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[-1][-1]
解题思路来源于代码随想录
「代码随想录」带你学透动态规划63. 不同路径 II - 不同路径 II - 力扣(LeetCode) (leetcode-cn.com)