返回

进阶学习LeetCode —— 动态规划(六)

见解分享

进阶学习LeetCode —— 动态规划(六)

探索63:不同路径 II

前言:动态规划的本质

动态规划是一种强大的算法范式,它善于解决具有重叠子问题和最优子结构特征的问题。在LeetCode 63题中,我们遇到的问题正是如此:从机器人出发,想要到达右下角,它有许多可能的路径,并且每条路径上的选择都会影响后续的可能性。如果我们使用暴力递归的方法,那么就会重复计算许多相同的子问题,导致时间复杂度呈指数级增长。

算法:动态规划解法

动态规划的思想是将问题分解成更小的子问题,并逐步求解这些子问题,最终得到整个问题的解。在LeetCode 63题中,我们可以将机器人从左上角到右下角的路径分为若干个子问题:从左上角到(1,0)、从左上角到(0,1)...从左上角到(m-1, n-1)。每个子问题的解都是基于其相邻子问题的解。

我们可以使用一个二维数组dp来存储这些子问题的解。dp[i][j]表示从左上角到(i, j)的路径数量。为了计算dp[i][j],我们需要考虑两个情况:

  1. 如果(i, j)存在障碍物,那么dp[i][j]为0。
  2. 如果(i, j)不存在障碍物,那么dp[i][j]等于从左上角到(i-1, j)的路径数量和从左上角到(i, j-1)的路径数量之和。

我们可以使用以下伪代码来动态规划的解法:

def uniquePathsWithObstacles(obstacleGrid):
  m, n = len(obstacleGrid), len(obstacleGrid[0])
  dp = [[0] * n for _ in range(m)]
  dp[0][0] = 1  # 初始化左上角的路径数量为1
  for i in range(m):
    for j in range(n):
      if obstacleGrid[i][j] == 1:  # 如果存在障碍物,则路径数量为0
        dp[i][j] = 0
      elif i == 0 or j == 0:  # 如果在第一行或第一列,则路径数量为1
        dp[i][j] = 1
      else:
        dp[i][j] = dp[i-1][j] + dp[i][j-1]  # 计算路径数量
  return dp[m-1][n-1]  # 返回从左上角到右下角的路径数量

复杂度分析

动态规划的解法的时间复杂度为O(mn),其中m和n分别是网格的行数和列数。空间复杂度也是O(mn),因为我们需要使用二维数组dp来存储子问题的解。

结语:算法的灵活性

动态规划是一种非常灵活的算法范式,它可以解决各种各样的问题。在LeetCode 63题中,我们使用动态规划来计算从左上角到右下角的不同路径数量。在其他问题中,我们可以使用动态规划来解决最长公共子序列、最短路径、最大子数组和等问题。

希望本文能够帮助您理解动态规划的思想和应用。如果您还有任何问题,欢迎随时提问。