代码随想录算法训练营第三十九天丨62. 不同路径、63. 不同路径 II

文章介绍了动态规划在计算从左上角到达矩阵任意位置的唯一路径数量问题中的应用,包括基本动态规划解决方案、滚动数组优化以及遇到障碍物时的处理方法。同时提到了两种优化策略:滚动数组和数论解法的思路。
摘要由CSDN通过智能技术生成

62. 不同路径

动态规划:

对于任意位置(i, j),到达这个位置的路径数量是到达(i-1, j)(i, j-1)的路径数量之和,因为只能从上方或左侧移动到达当前位置。这种结构允许我们通过组合子问题的解来解决整个问题。计算到达某一点的路径数量需要重复计算到达该点之前所有点的路径数量。使用动态规划存储这些中间结果可以避免重复计算,从而提高效率。因此这是典型的动态规划题。

状态dp[i][j]定义为从左上角(0, 0)到达位置(i, j)的唯一路径数量。这个状态是基于问题描述直接定义的。到达(i, j)的路径数量是从它的上方(i-1, j)和左侧(i, j-1)到达的路径数量之和。所有位于矩阵第一行dp[0][j]和第一列dp[i][0]的位置都被初始化为1,因为从起点到达这些位置只存在一条路径,要么一直向右,要么一直向下。数组是按行从上到下遍历的,每一行内部从左到右遍历。这种顺序确保在计算dp[i][j]时,dp[i-1][j]dp[i][j-1]都已经被计算过,保证了状态转移的正确性。

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        dp = [[1] * n for _ in range(m)]
        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[m - 1][n - 1]
 滚动数组优化:
class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        dp = [1] * n  # 初始化dp数组,长度为n,每个元素值为1
        for i in range(1, m):  # 从第二行开始遍历,因为第一行已经初始化
            for j in range(1, n):  # 从第二列开始遍历,第一列的值始终为1,不需要更新
                dp[j] += dp[j - 1]  # 更新dp[j],dp[j]的新值是它自己(代表上方的路径数)加上它左边的值(代表左方的路径数)
        return dp[-1]  # 返回最后一个元素,即到达右下角的路径数量

数论解法:

要从起点走到终点,总共需要走m−1步向下和n−1步向右,总步数为m−1+n−1。问题变成了,在这m+n−2步中,选择m−1步(或n−1步)来向下(或向右)走的方案数。

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        if m < n:
            m, n = n, m
        result = 1

        for i in range(1, n):
            result = result * (m + i - 1) // i
        return result

63. 不同路径 II

初始化dp:遇到石头停止初始化,石头的右边和下边不可达到。

递推式:如果当前位置是石头,置为0;如果不是石头,由左边和上边求和得到。

class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        dp = [[0] * n for _ in range(m)]
        for i in range(m):
            if obstacleGrid[i][0] == 1:
                break
            else:
                dp[i][0] = 1
        for j in range(n):
            if obstacleGrid[0][j] == 1:
                break
            else:
                dp[0][j] = 1

        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]
        return dp[m - 1][n - 1]
滚动数组优化:
class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        dp = [0] * n
        dp[0] = 1 if obstacleGrid[0][0] == 0 else 0

        for i in range(m):
            for j in range(n):
                if obstacleGrid[i][j] == 1:
                    dp[j] = 0
                elif j > 0:
                    dp[j] += dp[j - 1]
        return dp[n - 1]

今日总结:

两个题还是比较直观的,滚动数组优化还需要进一步学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值