漫画:动态规划系列 第四讲

漫画:动态规划系列 第四讲


在上一篇中,咱们经过题目“最长上升子序列”以及"最大子序和",学习了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上进行过测试运行,保证其严谨性!

相关文章
相关标签/搜索