题目描述:
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/triangle
问题分析:
这种题拿来一看就知道是动态规划算法了了。
首先我觉得贪心算法貌似不行
贪心的思想是,每次选取当前最短/最大的情况,直到最后得到最优方案。
因此,用动态规划来分析。
因为随着我们走,后边路径可能导致之前走过的路线不再是最优路径。
**
那么很快我们便有了一种解决问题的思路:**
思路:开辟同样大小的三角形(二维数组)
每个位置均保存来到当前位置的最短路径。
这样来看,更直观一点。
这个很容易了吧:
vv[ i ][ j ] = triangle[ i ][ j ] +
min(a[ i - 1 ][ j ] , vv[ i - 1 ][ j + 1 ]
因此,我们采用自底向上的分析法:
当前位置, 不是从正上方过来,必然从左上方的右边过来。
这样,能够得到二维实时路径长度的数组。我们再从最后一层中选出最小的即可。
我们的上述做法可以解决问题,但时空复杂的均为O(N^2)
2 那么来看优化
当我们每次从上边向下走时,遇到相等的就成了一个难题。
我们自底向上来走,这样无论如何都会走到triagle[0 ][ 0],不用担心多出口。
在自底向上走时,我们顺便保存一下当前的最短路径。
注意:核心想法来了:
既然我们只需要最优的一个路径,那么也就是说,我们每层保存的路径,用于求得新一层路径后后,就没啥暖用了,
那么 我们就将其覆盖掉,
因此 一维数组就可以保存当前层所有方格的最优路径了,
再准确点描述:当来到新一层计算好一个方格的最优路径后,就可以覆盖掉下面那层同列的最优路径了。
你明白了吗?
看看代码你一定就懂了。
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
vector<int> dp(triangle.size()+1,0);//初始化为0
//为什么需要多一个数组空间,因为每次取两个路径长度比较并提取其中最小的。
//自底向上
for(int i=triangle.size()-1; i>=0; i--)
{
for(int j=0; j<triangle[i].size(); j++)
{
//每求完一层,新一层数据一旦出来就可以覆盖掉
//原有数据了,(原数据用不上了)
dp[j] = min(dp[j],dp[j+1]) + triangle[i][j];
}
}
return dp[0];
}
};