漫畫:動態規劃系列 第四講

漫畫:動態規劃系列 第四講


在上一篇中,咱們經過題目「最長上升子序列」以及"最大子序和",學習了DP(動態規劃)在線性關係中的分析方法。這種分析方法,也在運籌學中被稱爲「線性動態規劃」,具體指的是 「目標函數爲特定變量的線性函數,約束是這些變量的線性不等式或等式,目的是求目標函數的最大值或最小值」。這點你們做爲了解便可,不須要死記,更不要生搬硬套!算法

在本節中,咱們將繼續分析一道略微區別於以前的題型,但願能夠由此題與以前的題目進行對比論證,進而順利求解!數組

01

第120題:三角形最小路徑和


第120題:給定一個三角形,找出自頂向下的最小路徑和。markdown


每一步只能移動到下一行中相鄰的結點上。ide

例如,給定三角形:函數

[學習

[2],

[3,4],

[6,5,7],測試

[4,1,8,3]優化

]code

自頂向下的最小路徑和爲 11(即,2 + 3 + 5 + 1 = 11)。blog


本題有必定難度!

若是沒有思路請回顧上一篇的學習內容!

不建議直接看題解!

02

自頂向下圖解分析


1156139D8_0.png
首先咱們分析題目,要找的是三角形最小路徑和,這是個啥意思呢?假設咱們有一個三角形:[[2], [3,4], [6,5,7], [4,1,8,3]]

漫畫:動態規劃系列 第四講
那從上到下的最小路徑和就是2-3-5-1,等於11。

因爲咱們是使用數組來定義一個三角形,因此便於咱們分析,咱們將三角形稍微進行改動:
漫畫:動態規劃系列 第四講

這樣至關於咱們將整個三角形進行了拉伸。這時候,咱們根據題目中給出的條件:每一步只能移動到下一行中相鄰的結點上。其實也就等同於,每一步咱們只能往下移動一格或者右下移動一格。將其轉化成代碼,假如2所在的元素位置爲[0,0],那咱們往下移動就只能移動到[1,0]或者[1,1]的位置上。假如5所在的位置爲[2,1],一樣也只能移動到[3,1]和[3,2]的位置上。以下圖所示:

漫畫:動態規劃系列 第四講

題目明確了以後,如今咱們開始進行分析。題目很明顯是一個找最優解的問題,而且能夠從子問題的最優解進行構建。因此咱們經過動態規劃進行求解。首先,咱們定義狀態:

dp[i][j] : 表示包含第i行j列元素的最小路徑和

咱們很容易想到能夠自頂向下進行分析。而且,不管最後的路徑是哪一條,它必定要通過最頂上的元素,即[0,0]。因此咱們須要對dp[0][0]進行初始化。

dp[0][0] = [0][0]位置所在的元素值

繼續分析,若是咱們要求dp[i][j],那麼其必定會從本身頭頂上的兩個元素移動而來。
漫畫:動態規劃系列 第四講

如5這個位置的最小路徑和,要麼是從2-3-5而來,要麼是從2-4-5而來。而後取兩條路徑和中較小的一個便可。進而咱們獲得狀態轉移方程:

dp[i][j] = min(dp[i-1][j-1],dp[i-1][j]) + triangle[i][j]

可是,咱們這裏會遇到一個問題!除了最頂上的元素以外,

漫畫:動態規劃系列 第四講

最左邊的元素只能從本身頭頂而來。(2-3-6-4)

漫畫:動態規劃系列 第四講

最右邊的元素只能從本身左上角而來。(2-4-7-3)

而後,咱們觀察發現,位於第2行的元素,都是特殊元素(由於都只能從[0,0]的元素走過來)

漫畫:動態規劃系列 第四講

咱們能夠直接將其特殊處理,獲得:

dp[1][0] = triangle[1][0] + triangle[0][0]

dp[1][1] = triangle[1][1] + triangle[0][0]

最後,咱們只要找到最後一行元素中,路徑和最小的一個,就是咱們的答案。即:

l:dp數組長度

result = min(dp[l-1,0],dp[l-1,1],dp[l-1,2]....)

綜上咱們就分析完了,咱們總共進行了4步:

1.定義狀態

2.總結狀態轉移方程

3.分析狀態轉移方程不能知足的特殊狀況。

4.獲得最終解

03

代碼分析


分析完畢,代碼自成:

1func minimumTotal(triangle [][]int) int {
 2    if len(triangle) < 1 {
 3        return 0
 4    }
 5    if len(triangle) == 1 {
 6        return triangle[0][0]
 7    }
 8    dp := make([][]int, len(triangle))
 9    for i, arr := range triangle {
10        dp[i] = make([]int, len(arr))
11    }
12    result := 1<<31 - 1
13    dp[0][0] = triangle[0][0]
14    dp[1][1] = triangle[1][1] + triangle[0][0]
15    dp[1][0] = triangle[1][0] + triangle[0][0]
16    for i := 2; i < len(triangle); i++ {
17        for j := 0; j < len(triangle[i]); j++ {
18            if j == 0 {
19                dp[i][j] = dp[i-1][j] + triangle[i][j]
20            } else if j == (len(triangle[i]) - 1) {
21                dp[i][j] = dp[i-1][j-1] + triangle[i][j]
22            } else {
23                dp[i][j] = min(dp[i-1][j-1], dp[i-1][j]) + triangle[i][j]
24            }
25        }  
26    }
27    for _,k := range dp[len(dp)-1] {
28        result = min(result, k)
29    }
30    return result
31}
32
33func min(a, b int) int {
34    if a > b {
35        return b
36    }
37    return a
38}

漫畫:動態規劃系列 第四講

運行上面的代碼,咱們發現使用的內存過大。咱們有沒有什麼辦法能夠壓縮內存呢?經過觀察咱們發現,在咱們自頂向下的過程當中,其實咱們只須要使用到上一層中已經累積計算完畢的數據,而且不會再次訪問以前的元素數據。繪製成圖以下:

漫畫:動態規劃系列 第四講

優化後的代碼以下:

1func minimumTotal(triangle [][]int) int {
 2    l := len(triangle)
 3    if l < 1 {
 4        return 0
 5    }
 6    if l == 1 {
 7        return triangle[0][0]
 8    }
 9    result := 1<<31 - 1
10    triangle[0][0] = triangle[0][0]
11    triangle[1][1] = triangle[1][1] + triangle[0][0]
12    triangle[1][0] = triangle[1][0] + triangle[0][0]
13    for i := 2; i < l; i++ {
14        for j := 0; j < len(triangle[i]); j++ {
15            if j == 0 {
16                triangle[i][j] = triangle[i-1][j] + triangle[i][j]
17            } else if j == (len(triangle[i]) - 1) {
18                triangle[i][j] = triangle[i-1][j-1] + triangle[i][j]
19            } else {
20                triangle[i][j] = min(triangle[i-1][j-1], triangle[i-1][j]) + triangle[i][j]
21            }
22        }  
23    }
24    for _,k := range triangle[l-1] {
25        result = min(result, k)
26    }
27    return result
28}
29
30func min(a, b int) int {
31    if a > b {
32        return b
33    }
34    return a
35}

漫畫:動態規劃系列 第四講

課後思考:如何自下而上求解?評論區留言吧!


注:本系列全部教程中都不會用到複雜的語言特性,你們不須要擔憂沒有學過go。算法思想最重要,使用go純屬本人愛好。同時,本系列全部代碼均在leetcode上進行過測試運行,保證其嚴謹性!

相關文章
相關標籤/搜索