题目描述
给定一个方形整数数组 A
,我们想要得到通过 A
的_下降路径_的最小和。
下降路径可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列。
样例
输入:[[1,2,3],[4,5,6],[7,8,9]]
输出:12
解释:
可能的下降路径有:
[1,4,7], [1,4,8], [1,5,7], [1,5,8], [1,5,9]
[2,4,7], [2,4,8], [2,5,7], [2,5,8], [2,5,9], [2,6,8], [2,6,9]
[3,5,7], [3,5,8], [3,5,9], [3,6,8], [3,6,9]
和最小的下降路径是 [1,4,7],所以答案是 12。
注意
1 <= A.length == A[0].length <= 100
-100 <= A[i][j] <= 100
。
算法
(动态规划) O(nm)
- f(i,j) 表示到达第 i 行第 j 列的时候的最小值。
- 转移时有三种方式,分别是从第 i−1 层的第 j−1,j 和 j+1 列到达第 i 层,即 f(i,j)=min(f(i−1,j−1),f(i−1,j),f(i−1,j+1))+a(i,j)。
- 初始值 f(0,j)=A(0,j),最终答案为 max。
时间复杂度
- 状态数为 nm 个,转移数为 3 个,故总时间复杂度为 O(nm)。
C++ 代码
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& A) {
int n = A.size(), m = A[0].size();
vector<vector<int>> f(n, vector<int>(m, 100000));
for (int j = 0; j < m; j++)
f[0][j] = A[0][j];
for (int i = 1; i < n; i++)
for (int j = 0; j < m; j++) {
f[i][j] = f[i - 1][j] + A[i][j];
if (j > 0)
f[i][j] = min(f[i][j], f[i - 1][j - 1] + A[i][j]);
if (j < m - 1)
f[i][j] = min(f[i][j], f[i - 1][j + 1] + A[i][j]);
}
int ans = 100000;
for (int j = 0; j < m; j++)
ans = min(ans, f[n - 1][j]);
return ans;
}
};
谢谢 wzc大佬!
补充一个压缩后的写法~
class Solution { public: int minFallingPathSum(vector<vector<int>>& A) { int n = A.size(), m = A[0].size(); vector<int> f(n, INT_MAX); vector<int> cur(m, INT_MAX); int ans = INT_MAX; for (int j = 0; j < m; j++) cur[j] = A[0][j]; for (int i = 1; i < n; i++) { for (int j = 0; j < m; j++) { f[j] = cur[j] + A[i][j]; if (j > 0) f[j] = min(f[j], cur[j - 1] + A[i][j]); if (j < m - 1) f[j] = min(f[j], cur[j + 1] + A[i][j]); } cur = f; } for (int j = 0; j < m; j++) ans = min(ans, cur[j]); return ans; } };