動態規劃解二維座標問題
動態規劃類題目分爲兩大類
- 求最優解
- 統計方案數
動態規劃中當前問題的最優解取決於子問題的最優解,當前問題的方案數取決於子問題的方案數
本文主要focus使用動態規劃解決二維座標中的狀態轉移問題。
prac63-不同路徑II
一個機器人位於一個 m x n 網格的左上角 (起始點在下圖中標記爲“Start” )。
機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記爲“Finish”)。
現在考慮網格中有障礙物。那麼從左上角到右下角將會有多少條不同的路徑?
輸入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
輸出: 2
解釋:
3x3 網格的正中間有一個障礙物。
從左上角到右下角一共有 2 條不同的路徑:
- 向右 -> 向右 -> 向下 -> 向下
- 向下 -> 向下 -> 向右 -> 向右
- 來源:力扣(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行,以此類推,使數組空間得到循環利用。