10.2 动态规划算法套路及空间优化 —— Climbing Stairs Unique Paths
這一篇文章從最簡單的動態規劃題目開始,結合上一節動態規劃三要素,以LeetCode兩道基礎的DP題目闡述DP問題的基本套路解法。
?
70.?Climbing Stairs
You are climbing a stair case. It takes?n?steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Note:?Given?n?will be a positive integer.
?
題目解析:
這是一道最基礎的動態規劃問題,用于我們初步了解。首先我們來回憶DP三大要素,抽煙喝酒燙頭,不,是最優子結構,狀態轉移方程和邊界。
下面我們看代碼實現,在dp問題中,對于f(i)我們一般存為數組dp.
class Solution:def climbStairs(self, n: int) -> int:# 特殊情況if n <= 2:return n# dp數組必備dp = [0] * (n+1)# 邊界dp[1] = 1dp[2] = 2for i in range(3, n+1):# 狀態轉移方程dp[i] = dp[i-1] + dp[i-2]return dp[-1]?
這個一維的問題就圖森破了,下面我們看經典的二維dp問題。說來說去,二維不一定比一維的就難,一維的數組也有很多難題。
62.?Unique Paths
A robot is located at the top-left corner of a?m?x?n?grid (marked 'Start' in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
How many possible unique paths are there?
?
題目解析:
我們仿照上題的思路來解析,看三大要素。f(i,j)表示到達i行j列的路徑數,f(m,n)即最終結果。i行j列是從左側或上邊走過來的,必然有一定的最優子結構的形式。那么接下來分析狀態轉移方程。和上一題類似,i行j列的上一步或者在i-1行j列,或者在i行j-1列,只有這兩種情況,且每種情況下只有一條路徑到i,j,因此直接得到f(i,j) = f(i-1,j) + f(i,j-1)。二維問題的邊界也在二維數組的邊界,下面我們直接看代碼實現:
class Solution:def uniquePaths(self, m: int, n: int) -> int:# dp數組dp = [[0] * n for _ in range(m)]# 邊界for i in range(m):dp[i][0] = 1for i in range(n):dp[0][i] = 1for i in range(1, m): for j in range(1, n):# 狀態轉移方程dp[i][j] = dp[i-1][j] + dp[i][j-1]return dp[m-1][n-1] # 或dp[-1][-1]再額外解釋一下邊界,沿著第一行或者第一列都是只有一種路徑,所以邊界的初始值都是1,也可以直接把dp數組初始化為1.
先充分的消化一下上面兩道問題的dp套路,從三要素理解解題思路,進而理解dp的核心思想,最優子結構和無后效性。
根據無后效性,下面我們看一下dp算法的優化思路。
以climbing stairs為例,基本思路中我們定義了長度為n的數組用于存儲i處的最終解,時間復雜度O(n);但是從關系式dp[i] = dp[i-1] + dp[i-2]可以看出,在i處我們只需要i-1和i-2的值,更早的值我們不需要了,這就體現了無后效性,因此我們只需要三個變量即可解決問題,下面看代碼:
class Solution:def climbStairs(self, n: int) -> int:if n <= 2:return npre1 = 2pre2 = 1dp = 0for i in range(3, n+1): dp = pre1 + pre2pre2, pre1 = pre1, dpreturn dp就是這樣,將空間復雜度降到了O(1)。我們再看unique paths題目的優化。
對于第i行第j列,我們看關系式 f(i,j) = f(i-1,j) + f(i,j-1),在前面的解法中,我們的空間復雜度是O(m*n),對于每個位置來說,我們需要左邊的和上邊的,對于每一行來說,我們只需要上一行的結果即可。因此我們可以將空間復雜度降到O(n),結合下面代碼來看,我們只定義一個一維dp數組,在每行遍歷中,不斷更新dp數組的值,不斷拋棄上一行的結果,直到最后一行。
class Solution:def uniquePaths(self, m: int, n: int) -> int:# 定義一維dp數組,同時初始化了第一行的邊界值dp = [1] * nfor i in range(1, m): for j in range(n):# 第一列的邊界if j == 0:dp[j] = 1else:# 相當于原狀態轉移方程,不斷更新dp數組值dp[j] += dp[j-1]return dp[-1]?
總結
以上是生活随笔為你收集整理的10.2 动态规划算法套路及空间优化 —— Climbing Stairs Unique Paths的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .net中mvc问卷制作
- 下一篇: 如何选购电脑主板?