给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
规定每次只能向下或者向右移动一步。
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
动态规划:
1、由于路径只能向右或者向下,因此第一行和第一列的路径是唯一的,只需要把对应的元素值相加即可。
2、对于不是第一行和第一列的元素,可以从上方的元素向下移动或者左方的元素向右移动到达,到达该元素位置的最小路径等于其上方或者左方的最小值加上当前元素的值。
3、创建二维数组 dp,与原始网格的大小相同,dp[i][j] 表示从左上角出发到 (i,j) 位置的最小路径和。显然,dp[0][0]=grid[0][0]。对于 dp 中的其余元素,通过以下状态转移方程计算元素值。
- 当 i>0 且 j=0 时,dp[i][0] = dp[i-1][0] + grid[i][0]。
- 当 i=0 且 j>0 时,dp[0][j] = dp[0][j-1] + grid[0][j]。
- 当 i>0 且 j>0 时,dp[i][j] = min(dp[i−1][j],dp[i][j−1]) + grid[i][j]。
#define ROW 3
#define COL 3
int minPathSum(vector<vector<int> >& matrix)
{
const int row = matrix.size();
const int col = matrix[0].size();
int dp[ROW][COL]; //dp[i][j]表示,从[0,0]开始,走到[i,j]的最小路径和
//初始化第一列和第一行
dp[0][0] = matrix[0][0];
for (int i = 1; i < row; ++i)
dp[i][0] = dp[i - 1][0] + matrix[i][0];
for (int i = 1; i < col; ++i)
dp[0][i] = dp[0][i - 1] + matrix[0][i];
//除了第一行第一列之外的其他元素
for (int i = 1; i < row; ++i)
for (int j = 1; j < col; ++j)
dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + matrix[i][j];
return dp[row - 1][col - 1];
}
复杂度:
时间复杂度:O(m*n),其中 m 和 n 分别是网格的行数和列数。需要对整个网格遍历一次,计算 dp 的每个元素的值。
空间复杂度:O(m*n),其中 m 和 n 分别是网格的行数和列数。创建一个二维数组 dp,和网格大小相同。
注:空间复杂度可以优化,例如每次只存储上一行的 dp 值,则可以将空间复杂度优化到 O(n)。