【刷题LeetCode】奇妙动态规划——不同路径II

动态规划解二维坐标问题

  • prac63-不同路径II
  • 滚动数组思想

动态规划类题目分为两大类

  • 求最优解
  • 统计方案数
    动态规划中当前问题的最优解取决于子问题的最优解,当前问题的方案数取决于子问题的方案数
    本文主要focus使用动态规划解决二维坐标中的状态转移问题。

prac63-不同路径II

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:

  1. 向右 -> 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右 -> 向右
  3. 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/unique-paths-ii 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

由于题目描述中机器人只能向下/向右移动一步,因此当前状态仅与之前状态有关。
使用dp[i][j]表示从坐标(0,0)到坐标(i,j)的路径总数,如果坐标(i,j)可行,则
dp[i][j] = dp[i-1][j] + dp[i][j-1]
此时时间复杂度和空间复杂度均为O(mn),官方采用滚动数组思想进行优化,将空间复杂度优化为O(m)

class Solution:
    """动态规划"""
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        n = len(obstacleGrid)
        m = len(obstacleGrid[0])
        dp = [0]*m
        if obstacleGrid[0][0] == 0:
            dp[0] = 1
        else:
            dp[0] = 0
        for i in range(n):
            for j in range(m):
                if obstacleGrid[i][j] == 1:
                    dp[j] = 0
                    continue
                if j-1 >= 0:
                    dp[j] += dp[j-1]
        return dp[m-1]


if __name__ == '__main__':
    obstacleGrid = [
                      [0,0,0],
                      [0,1,0],
                      [0,0,0]
                    ]
    sl = Solution()
    print(sl.uniquePathsWithObstacles(obstacleGrid)) # console:2

滚动数组思想

滚动数组思想即通过固定的几个存储空间,来达到压缩存储空间的作用。

就以prac63题为例,考虑到每个dp[i][j]都仅和dp[i-1][j]和dp[i][j-1]有关,我们将dp[0][j]状态存在二维表中,接着递推dp[1][j],再接着递推dp[2][j]的状态时,保存dp[0][1]的状态已经没有保存意义了,所以直接保存dp[2][j]的状态保存到二维表的第0行,以此类推,使数组空间得到循环利用。

动态规划及空间压缩的滚动数组法详解

你可能感兴趣的:(学习日记,数据结构与算法)