python--lintcode109.數字三角形(動態規劃)
描述
給定一個數字三角形,找到從頂部到底部的最小路徑和。每一步可以移動到下面一行的相鄰數字上。
如果你只用額外空間複雜度O(n)的條件下完成可以獲得加分,其中n是數字三角形的總行數。
您在真實的面試中是否遇到過這個題? 是
樣例
比如,給出下列數字三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
從頂到底部的最小路徑和為11 ( 2 + 3 + 5 + 1 = 11)。
兄弟們,今天我們就正式進入動態規劃的環節了,動態規劃很有意思,也很難,今天就簡單介紹下思路。
我們在碰到一個題目的時候,首先要思考,這一題要用動態規劃嗎?
動態規劃適用的三個場景:
1、求最大值最小值
2、判斷是否可行
3、統計方案個數
動態規劃不適用的三個場景:
1、求出所有具體方案而非方案個數
2、輸入資料時一個集合(無序),而不是一個序列(有序)。
3、暴力演算法的時間複雜度已經是多項式級別。動態規劃擅長優化指數級別複雜度(2^n,n!)到多項式級別複雜度(n^2,n^3),不擅長優化從n^3到n^2。
那麼動態規劃的思路是什麼呢?主要分四步:
1、狀態 state
靈感,創造力,儲存小規模問題的結果
2、方程 function
狀態之間的聯絡,怎麼通過小的狀態,來算大的狀態
3、初始化 initialization
最極限的小狀態是什麼,起點
4、答案 answer
最大的那個狀態是什麼,終點
OK,說完了動態規劃,我們來看這一題。這一題很明顯是動態規劃每一個條件都符合,當然用dfs也可以做,但是如果用dfs做的話,時間複雜度是2^n。
這一題的思路是如何?對於一個結點來說,它的前序結點一定是它上一行的左邊或者右邊,要想讓到這個結點的路徑最小,那麼到它的前序結點的路徑也一定是最小的。
那麼遞推式已經出來了:每個結點的最短路徑=min(左父結點最短路徑,右父節點最短路徑)+該結點本身權重
具體看程式碼,我註釋寫得很詳細了:
class Solution: """ @param triangle: a list of lists of integers @return: An integer, minimum path sum """ def minimumTotal(self, triangle): # write your code here if (len(triangle)==0 or triangle==None):return 0 dp=[] for i in range(len(triangle)): temp = [] for j in range(len(triangle[i])): temp.append(0) dp.append(temp) dp[0][0]=triangle[0][0] # dp陣列中存的是每個座標從頂往下的最短路徑 # 每個數字的前一條路,要麼從左上來,要麼從右上來 # 左上座標為row-1,column-1 # 右上座標為row-1,column # 每行第一列沒有左上,只有右上 for j in range(1,len(triangle)): dp[j][0]=dp[j-1][0]+triangle[j][0] # 每行最後一列沒有右上,只有左上 for j in range(1,len(triangle)): dp[j][-1]=dp[j-1][-1]+triangle[j][-1] for i in range(1,len(triangle)): for j in range(1,len(triangle[i])-1): # 存最短路徑:每個座標的最短路徑=其前序結點的最短路徑+該結點本身 dp[i][j]=min(dp[i-1][j-1],dp[i-1][j])+triangle[i][j] #找出最後一行中最小的 length=len(triangle)-1 minnum=99999999 for i in range(len(dp[length])): if(dp[length][i]<minnum): minnum=dp[length][i] return minnum s=Solution() print(s.minimumTotal([ [2], [3,4], [6,5,7], [4,1,8,3] ]))