题目描述
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形(用二维向量triangle表示):
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
算法
如果没有复杂度要求的话,可以开一个二维数组dp[n][n],n是三角形的行数。从上至下的更新情况下所示:
[
[2],
[5,6],
[11,10,13],
[15,11,18,13]
]
最终返回的是dp的最后一行中最小的那个数。
现在要求空间复杂度为O(n),即最多只能开一个一维数组dp[n],n是三角形的行数。可以将dp中的数加到triangle中对应的行,最后再将triangle中对应的该行重新保存回dp。一位triangle一行最多保存n个数,所以dp[n]已经够用。详细注释在代码中给出。
代码
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int size = triangle.size();
// 边界条件,若triangle仅有一行,直接返回第一行的该数即可
if(size == 1)
return triangle[0][0];
// 开dp数组
int dp[size];
dp[0] = triangle[0][0];
// 自三角形的第二行从上到下遍历,体现在下标为i=1。因为二维向量由i=0开始,i=0代表第一行,这里不要搞混了。
for (int i = 1; i < size; i++)
{
// 从前往后遍历triangle[i]这个向量,并用已经保存的dp数组更新triangle[i]
for (int j = 0; j <= i; j++)
{
if(j == 0)
triangle[i][j] += dp[j];
else if(j == i)
triangle[i][j] += dp[j-1];
else
triangle[i][j] += min(dp[j], dp[j-1]);
}
// 重新保存回dp数组,以用来更新三角形的下一行
for (int j = 0; j < triangle[i].size(); j++)
dp[j] = triangle[i][j];
}
// 取dp中最小的那个数返回
int _min = 99999999;
for (int j = 0; j < size; j++)
if(_min > dp[j])
_min = dp[j];
return _min;
}
};