【代码随想录】d42-动态规划-part02-python

1. 62. 不同路径

1.1题目及讲解

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
示例 1:
【代码随想录】d42-动态规划-part02-python_第1张图片

  • 输入:m = 3, n = 7
  • 输出:28

示例 2:

  • 输入:m = 3, n = 2
  • 输出:3
  • 解释:
    从左上角开始,总共有 3 条路径可以到达右下角。
    1. 向右 -> 向下 -> 向下
    2. 向下 -> 向下 -> 向右
    3. 向下 -> 向右 -> 向下

示例 3:

  • 输入:m = 7, n = 3
  • 输出:28

示例 4:

  • 输入:m = 3, n = 3
  • 输出:6

提示:

  • 1 <= m, n <= 100
  • 题目数据保证答案小于等于 2 * 109

题目链接/文章讲解:https://programmercarl.com/0062.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84.html
视频讲解:https://www.bilibili.com/video/BV1ve4y1x7Eu

1.2代码实现

思路:

  1. 确定dp数组以及下标的含义
    dp[i][j]表示到达位置[i,j]的路径有dp[i][j]种
  2. 确定递推公式
    由于只能从上或者从右到位置[i,j]
    [i-1,j]向下走一步到[i,j],[i,j-1]向右走一步到[i,j],所以到[i,j]位置的路径有dp[i-1][j]+dp[i][j-1]种
    推导公式为 :dp[i][j]=dp[i-1][j]+dp[i][j-1]
  3. dp数组如何初始化
    通过推导公式可得,dp[i][j]需要通过其上方及左侧的值得出,所以初始化时,需要将第一行,第一列全部初始化
    dp[0][j] = 1;
    dp[i][0] = 1;
  4. 确定遍历顺序
    遍历顺序则是从起点由上向下,由左到右
  5. 举例推导dp数组
    【代码随想录】d42-动态规划-part02-python_第2张图片
m = 3
n = 8


def fun():
    # 初始化
    dp = [[0]*n for _ in range(m)]  # 创建一个二维列表用于存储唯一路径数
    for i in range(m):
        dp[i][0] = 1
    for j in range(n):
        dp[0][j] = 1
    # 计算每个单元格的唯一路径数
    for i in range(1, m):  # 初始化时已经计算了位置dp[0][j]和dp[i][0]的路径个数,所以下面的遍历不能从0开始了
        for j in range(1, n):
            dp[i][j] = dp[i-1][j]+dp[i][j-1]
    # print(dp)
    return dp[-1][-1]  # 返回右下角单元格的唯一路径数


print(fun())

2. 63. 不同路径 II

2.1题目及讲解

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

示例 1:
【代码随想录】d42-动态规划-part02-python_第3张图片

  • 输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
  • 输出:2
  • 解释:3x3 网格的正中间有一个障碍物。
    从左上角到右下角一共有 2 条不同的路径:
    1. 向右 -> 向右 -> 向下 -> 向下
    2. 向下 -> 向下 -> 向右 -> 向右

示例 2:
【代码随想录】d42-动态规划-part02-python_第4张图片

  • 输入:obstacleGrid = [[0,1],[0,0]]
  • 输出:1

提示:

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

题目链接/文章讲解:https://programmercarl.com/0063.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84II.html
视频讲解:https://www.bilibili.com/video/BV1Ld4y1k7c6

2.2代码实现

思路:

  1. 确定dp数组以及下标的含义
    dp[i][j]表示到达位置[i,j]的路径有dp[i][j]种
  2. 确定递推公式
    由于只能从上或者从右到位置[i,j]
    [i-1,j]向下走一步到[i,j],[i,j-1]向右走一步到[i,j],所以到[i,j]位置的路径有dp[i-1][j]+dp[i][j-1]种
    推导公式为 :dp[i][j]=dp[i-1][j]+dp[i][j-1]
    因为有了障碍,(i, j)如果是障碍的话应该就保持初始状态(初始状态为0)
  3. dp数组初始化
    因为从(0, 0)的位置到(i, 0)的路径只有一条,所以dp[i][0]一定为1,dp[0][j]也同理。
    但如果(i, 0) 这条边有了障碍之后,障碍之后(包括障碍)都是走不到的位置了,所以障碍之后的dp[i][0]应该还是初始值0。
    【代码随想录】d42-动态规划-part02-python_第5张图片
  4. 确定遍历顺序
    从递归公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 中可以看出,一定是从左到右一层一层遍历,这样保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值。
  5. 举例推导dp数组
    拿示例1来举例如题:
    【代码随想录】d42-动态规划-part02-python_第6张图片
    对应的dp table 如图:
    【代码随想录】d42-动态规划-part02-python_第7张图片
obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]


def fun():
    # 特殊情况,起始位置或者终止位置有障碍物,那么就无法出发或无法到达
    if obstacleGrid[0][0] == 1 or obstacleGrid[-1][-1] == 1:
        return 0
    # dp数组初始化
    m = len(obstacleGrid)
    n = len(obstacleGrid[0])
    dp = [[0] * n for _ in range(m)]  # 创建一个二维列表用于存储路径数
    for i in range(m):
        if obstacleGrid[i][0] == 1:  # 遇到障碍物就不初始了,障碍物后面的位置也不初始化了
            break
        dp[i][0] = 1
    for j in range(n):
        if obstacleGrid[0][j] == 1:
            break
        dp[0][j] = 1
    # print(dp)
    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]
    # print(dp)
    return dp[-1][-1]


print(fun())

你可能感兴趣的:(动态规划,python,算法)