题号 120
题目描述
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
相邻的结点 在这里指的是 下标
与 上一层结点下标
相同或者等于 上一层结点下标 + 1
的两个结点。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
小路径和为 11
(即,2 + 3 + 5 + 1 = 11)。
解题思路一——动态规划
Step1、2:描述问题的最优解结构特征,递归定义最优解值
设 f[i][j] 表示从三角形顶点走到点(i, j)位置的最小路径和,以上方示例为例,标号规则如下:
0 | 1 | 2 | 3 | |
0 | 2 | |||
1 | 3 | 4 | ||
2 | 6 | 5 | 7 | |
3 | 5 | 1 | 8 | 3 |
对于点(i, j)而言,只可能通过(i-1, j-1) 和 (i-1, j)两个点到达,则:
f(i, j) = min(f(i-1, j-1), f(i-1, j)) + c(i, j)
其中c(i, j)表示点(i, j)处的数值。
几个特殊位置:
(1)f(0, 0) = c(0, 0)
(2)当 j = 0 时:
点(i, 0)只可能通过点(i-1, 0)到达,所以:
f(i, 0) = f(i-1, 0) + c(i, 0)
(3)当 j = i 时:
点(i, i)只可能通过点(i-1, i-1)到达,所以:
f(i, i) = f(i-1)(i-1) + c(i)(i)
Step3、4:自底向上计算最优解值、输出最优解值
问题的解就是从顶点到三角形最后一行各点的最小路径和中最小的那一个。
代码实现如下:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<vector<int>> f(n, vector<int>(n));
f[0][0] = triangle[0][0];
for(int i = 1; i < n; i++)
for (int j = 0; j < triangle[i].size(); j++) {
if (j == 0) {
f[i][j] = f[i - 1][j] + triangle[i][j];
}
else if (j == i) {
f[i][j] = f[i - 1][j - 1] + triangle[i][j];
}
else
{
f[i][j] = min(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j];
}
}
int ans = f[n - 1][0];
for (int i = 1; i < f[n - 1].size(); i++) {
if (f[n - 1][i] < ans) {
ans = f[n - 1][i];
}
}
return ans;
}
};
时间复杂度:O(n^2)
空间复杂度:O(n^2)
代码优化:(来自:三角形最小路径和)
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<vector<int>> f(n, vector<int>(n));
f[0][0] = triangle[0][0];
for (int i = 1; i < n; ++i) {
f[i][0] = f[i - 1][0] + triangle[i][0];
for (int j = 1; j < i; ++j) {
f[i][j] = min(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j];
}
f[i][i] = f[i - 1][i - 1] + triangle[i][i];
}
return *min_element(f[n - 1].begin(), f[n - 1].end());
}
};