欢迎访问LeetCode题解合集
题目描述
给定一个三角形 triangle
,找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i
,那么下一步可以移动到下一行的下标 i
或 i + 1
。
示例 1:
输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出:11
解释:如下面简图所示:
2
3 4
6 5 7
4 1 8 3
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
示例 2:
输入:triangle = [[-10]]
输出:-10
提示:
-
1 <= triangle.length <= 200
-
triangle[0].length == 1
-
triangle[i].length == triangle[i - 1].length + 1
-
$-10^4 \le triangle[i][j] \le 10^4$
进阶:
- 你可以只使用
O(n)
的额外空间(n
为三角形的总行数)来解决这个问题吗?
题解:
动态规划。
法一:
自顶向下。
设 f[i][j]
表示从 (1,1)
走到 (i,j)
的最小路径和,则转移方程为 f[i][j] = min( f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j]
。
时间复杂度:$O(n^2)$
额外空间复杂度:$O(n)$
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<vector<int>> f( n );
f[0] = vector<int>{triangle[0][0]};
for ( int i = 1; i < n; ++i ) {
f[i].resize( i + 1 );
f[i][0] = triangle[i][0] + f[i - 1][0];
f[i][i] = triangle[i][i] + f[i - 1][i - 1];
for ( int j = 1; j < i; ++j )
f[i][j] = min( f[i - 1][j - 1], f[i - 1][j] ) + triangle[i][j];
}
int min_val = f[n - 1][0];
for ( int j = 1; j < n; ++j ) min_val = min( min_val, f[n - 1][j] );
return min_val;
// return *min_element( f[n - 1].begin(), f[n - 1].end() );
}
};
/*
时间:4ms,击败:97.98%
内存:8.3MB,击败:81.28%
*/
可以发现,f[i][j]
只跟 f[i - 1][j - 1]
和 f[i - 1][j]
有关,可以使用滚动数组优化:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<int> f;
f.emplace_back( triangle[0][0] );
int pre, tmp;
for ( int i = 1; i < n; ++i ) {
f.emplace_back( f[i - 1] );
pre = f[0];
f[0] += triangle[i][0];
f[i] += triangle[i][i];
for ( int j = 1; j < i; ++j ) {
tmp = f[j];
f[j] = min( f[j], pre ) + triangle[i][j];
pre = tmp;
}
}
int min_val = f[0];
for ( int j = 1; j < n; ++j ) min_val = min( min_val, f[j] );
return min_val;
}
};
/*
时间:4ms,击败:97.98%
内存:8.2MB,击败:91.44%
*/
法二:
自底向上。
设 f[i][j]
表示从底层走到 (i,j)
的最小路径和,则转移方程为 f[i][j] = min( f[i + 1][j + 1], f[i + 1][j]) + triangle[i][j]
。
时间复杂度:$O(n^2)$
额外空间复杂度:$O(n)$
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<vector<int>> f( n );
f[n - 1] = triangle[n - 1];
for ( int i = n - 2; i >= 0; --i ) {
f[i].resize( i + 1 );
for ( int j = 0; j <= i; ++j )
f[i][j] = min( f[i + 1][j], f[i + 1][j + 1] ) + triangle[i][j];
}
return f[0][0];
}
};
/*
时间:4ms,击败:97.98%
内存:8.4MB,击败:77.57%
*/
可以使用滚动数组优化:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<int> f = triangle[n - 1];
for ( int i = n - 2; i >= 0; --i ) {
for ( int j = 0; j <= i; ++j )
f[j] = min( f[j], f[j + 1] ) + triangle[i][j];
}
return f[0];
}
};
/*
时间:4ms,击败:97.98%
内存:8.1MB,击败:93.82%
*/