题目描述
给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。
下降路径可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置(row, col)的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col + 1) 。
解题思路
这个问题是一个典型的动态规划(Dynamic Programming, DP)问题。动态规划通常用于解决那些可以通过将原问题分解为较小子问题,然后解决这些子问题来解决整个问题的情况。在这个问题中,我们可以从最后一行开始向上回溯,计算到达每一行每一列的最小路径和。
步骤
- 初始化 :
- 创建一个同样大小的DP数组(
dp
),用于存储到达每个位置的最小路径和。 - 将DP数组的第一行初始化为矩阵的第一行,因为从第一行开始没有选择,只能取矩阵本身的值。
- 创建一个同样大小的DP数组(
- 填充DP数组 :
- 从第二行开始,遍历矩阵的每一行和每一列。
- 对于每个位置
(i, j)
(i
表示行,j
表示列),计算从下一行(i+1, j-1)
、(i+1, j)
、(i+1, j+1)
中选择的最小路径和,并将这个最小路径和加上当前位置的值matrix[i][j]
,存入dp[i][j]
。 - 注意边界条件:当
j-1 < 0
或j+1 >= n
时,需要忽略不存在的位置。
- 找出最小值 :
- 遍历DP数组的最后一行,找出其中的最小值,即为所求的最小路径和。
cpp
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& matrix) {
int n = matrix.size();
vector<vector<int>> dp(n, vector<int>(n, 0));
// 初始化dp数组的第一行为matrix的第一行
for (int j = 0; j < n; ++j) {
dp[0][j] = matrix[0][j];
}
for (int i = 1; i < n; i++) {
for (int j = 0; j < n; ++j) {
// 计算从下一行到当前位置的最小路径和
int minNext = INT_MAX;
// 考虑从正下方和左右对角线的下一个位置(如果存在)
for (int k = max(0, j - 1); k <= min(n - 1, j + 1); ++k) {
minNext = min(minNext, dp[i - 1][k]);
}
// 更新dp[i][j]为当前位置的值加上从下一行到当前位置的最小路径和
dp[i][j] = matrix[i][j] + minNext;
}
}
int ret = dp[n - 1][0];
for (int i = 1; i < n; i++) {
if (ret >= dp[n - 1][i])
ret = dp[n - 1][i];
}
return ret;
}
};
复杂度分析
- 时间复杂度:O(n^2),其中 n 是矩阵的维度。因为我们需要遍历矩阵的每个元素一次来填充DP数组,并再次遍历DP数组的最后一行来找出最小值。
- 空间复杂度:O(n^2),用于存储DP数组。