每日一题:不同路径(leetcode62、63)

本文介绍了使用深度优先搜索(DFS)和动态规划(DP)解决LeetCode中的62.不同路径和63.不同路径II问题。在62题中,通过DFS和DP两种方法找到从起点到终点的不同路径数;在63题中,加入了障碍物,使用DP解决时需要考虑障碍对路径的影响,初始化和遍历顺序更为关键。
摘要由CSDN通过智能技术生成

题目: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]

解题思路来源于代码随想录

动态规划:不同路径 (qq.com) 


题目: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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值