【刷題LeetCode】奇妙動態規劃——不同路徑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行,以此類推,使數組空間得到循環利用。

動態規劃及空間壓縮的滾動數組法詳解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章