1. 程式人生 > >python--lintcode109.數字三角形(動態規劃)

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]
]))