1. 题⽬链接:931.下降路径最⼩和
2. 题⽬描述:
3. 解法(动态规划):
算法思路:
关于这⼀类题,由于我们做过类似的,因此「状态表⽰」以及「状态转移」是⽐较容易分析出来的。 ⽐较难的地⽅可能就是对于「边界条件」的处理。
1. 状态表⽰:
对于这种「路径类」的问题,我们的状态表⽰⼀般有两种形式:
i. 从[i, j] 位置出发,到达⽬标位置有多少种⽅式;
ii. 从起始位置出发,到达[i, j] 位置,⼀共有多少种⽅式
这⾥选择第⼆种定义状态表⽰的⽅式: dp[i][j] 表⽰:到达[i, j] 位置时,所有下降路径中的最⼩和。
2. 状态转移⽅程:
对于普遍位置[i, j] ,根据题意得,到达[i, j] 位置可能有三种情况:
i. 从正上⽅[i - 1, j] 位置转移到[i, j] 位置;
ii. 从左上⽅[i - 1, j - 1] 位置转移到[i, j] 位置;
iii. 从右上⽅[i - 1, j + 1] 位置转移到[i, j] 位置;
我们要的是三种情况下的「最⼩值」,然后再加上矩阵在[i, j] 位置的值。 于是 dp[i][j] = min(dp[i - 1][j], min(dp[i - 1][j - 1], dp[i - 1][j + 1])) + matrix[i][j] 。
3. 初始化:
可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。
使⽤这种技巧要注意两个点:
i. 辅助结点⾥⾯的值要「保证后续填表是正确的」;
ii. 「下标的映射关系」。
在本题中,需要「加上⼀⾏」,并且「加上两列」。所有的位置都初始化为⽆穷⼤,然后将第⼀⾏ 初始化为0 即可。
4. 填表顺序:
根据「状态表⽰」,填表的顺序是「从上往下」。
5. 返回值:
注意这⾥不是返回dp[m][n] 的值!
题⽬要求「只要到达最后⼀⾏」就⾏了,因此这⾥应该返回「dp表中最后⼀⾏的最⼩值」。
C++算法代码:
class Solution
{
public:
int minFallingPathSum(vector<vector<int>>& matrix)
{
int m=matrix.size(),n=matrix[0].size();
vector<vector<int>>dp(m+1,vector<int>(n+2,INT_MAX));
// 初始化第⼀⾏
for(int j = 0; j < n + 2; j++)
{
dp[0][j] = 0;
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i-1][j+1]))+matrix[i-1][j-1];
}
}
int min_num=INT_MAX;
for(int j=1;j<=n;j++)
{
min_num=min(min_num,dp[m][j]);
}
return min_num;
}
};
Java算法代码:
class Solution
{
public int minFallingPathSum(int[][] matrix)
{
// 1. 创建 dp 表
// 2. 初始化
// 3. 填表
// 4. 返回结果
int n = matrix.length;
int[][] dp = new int[n + 1][n + 2];
for (int i = 1; i <= n; i++) dp[i][0] = dp[i][n + 1] =
Integer.MAX_VALUE;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i - 1][j - 1],
dp[i - 1][j + 1])) + matrix[i - 1][j - 1];
int ret = Integer.MAX_VALUE;
for (int j = 1; j <= n; j++)
ret = Math.min(ret, dp[n][j]);
return ret;
}
}