力扣原题链接,点击跳转。
有一个n×n的方阵matrix。从这个矩阵的最上面那一行的某一个元素开始,下降到最下面那一行的某一个元素。每次只能走到左下方、正下方和右下方这三者之一,也就是说,从(i,j)只能到达(i+1,j-1)、(i+1,j)和(i+1,j+1)这三者之一。请问,经过的路径上的所有元素的最小和是多少?
我们用动态规划来解决这个问题。创建dp表,先确定状态表示,我们用dp[i][j]表示下降到(i,j)位置的最小和。那么,考虑最近的一步,只有可能是从左上方、正上方和右上方这三者之一下降到该位置。也就是说,要想下降到(i,j),可以先从最上面那一行下降到(i-1,j-1)、(i-1,j)和(i-1,j+1)这三者之一,再下降到(i,j),再根据要求的是最小和,推导出状态转移方程:dp[i][j]=min(dp[i-1][j-1]+matrix[i][j],dp[i-1][j]+matrix[i][j],dp[i-1][j+1]+matrix[i][j])=min(dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1])+matrix[i][j]。
接着考虑初始化的问题。为了防止越界,需要提前初始化最左边那一列、最上面那一行和最右边那一列。
? ? ? ? ? ? ? ? ? ? ? ?
? ?
? ?
? ?
? ?
? ?
? ?
为了更加优雅地解决这个问题,我们在最左边、最上边和最右边加上两列一行。
* * * * * * * * * * * * * *
* ? ? ? ? ? ? ? ? ? ? ? ? *
* ? ? *
* ? ? *
* ? ? *
* ? ? *
* ? ? *
* ? ? *
显然,dp的第一行?和matrix的第一行是相同的。为了满足:dp的每一个位置都是上边的三个位置的最小值加上matrix这个位置的值,可以把第一行初始化成0。
0 0 0 0 0 0 0 0 0 0 0 0 0 0
* ? ? ? ? ? ? ? ? ? ? ? ? *
* ? ? *
* ? ? *
* ? ? *
* ? ? *
* ? ? *
* ? ? *
求每个位置上边三个位置的最小值时,最左边和最右边两列的*不能影响结果,只需要把这些*初始化成+∞。由于在原来的dp表中加上了两列一行,dp表的(i,j)应该对应matrix的(i-1,j-1)。根据状态转移方程,每个位置的值只和上边的3个数相关,所以应从上往下填表,确保在填到某一个位置时,它上边的三个位置的值已经填完了。最后,应返回dp表最后一行的最小值。
class Solution
{
public:int minFallingPathSum(vector<vector<int>>& matrix){int n = matrix.size();// 创建dp表vector<vector<int>> dp(n + 1, vector<int>(n + 2, INT_MAX));// 初始化for (int i = 0; i < n + 2; i++)dp[0][i] = 0;// 填表for (int i = 1; i <= n; 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];// 求dp表最后一行的最小值int ret = INT_MAX;for (int i = 1; i <= n; i++)ret = min(ret, dp[n][i]);return ret;}
};