题目:给定一个矩阵,从左上角开始每次只能向右或者向下移动,最后到达右下角的位置,路径上的所有的数字累加起来作为这条路径的路劲和。要求返回所有路径和中的最小路径和。
举例:
路径1,3,1,0,6,1,0是所有路径中路径和最小的,所以返回其和12。
解析:
这个题目很类似之前的那个动态规划的数字三角的问题。毫无疑问的,这个问题也是用动态规划解决。只要确定了状态和转移方程,这个题目很容易解决。下面直接给出代码:
//利用path记录路径,对于每一个path[i][j],0代表dp[i][j]的值从上面加过来,1代表dp[i][j]的值从左边加过来
int minPathSum1(int matrix[][col], int dp[][col], int path[][col])
{
if(matrix == NULL)
{
return 0;
}
dp[0][0] = matrix[0][0];
//计算第一列的值
for(int i = 1; i < row; i ++)
{
dp[i][0] = dp[i - 1][0] + matrix[i][0];
path[i][0] = 0;
}
//计算第一行的值
for(int j = 1; j < col; j++)
{
dp[0][j] = dp[0][j- 1] + matrix[0][j];
path[0][j] = 1;
}
//计算其它的值
for(int i = 1; i < row; i++)
{
for(int j = 1; j < col; j++)
{
int direction = dp[i][j-1] < dp[i-1][j] ? 1 : 0;
dp[i][j] = (direction ? dp[i][j-1] : dp[i-1][j]) + matrix[i][j];
path[i][j] = direction;
}
}//for
return dp[row - 1][col - 1];
}
这里在dp上存储每个点的最短路径和,在path上存储这个最短路径是哪个点过来的。这样就能在找到最短路径和的同时,把路径一块找到。
二维动态规划的空间压缩
上面的题目很简单,不是这篇文章的重点,下面来看一下二维动态规划的空间压缩问题。上面的动态规划的时间复杂度是O(M*N),空间复杂度就是二维数组的大小O(M*N)。空间压缩的方法是不用记录所有的子问题的解。所以就可以只用一个行数组记录第一行、第二行...一次计算。直到最后一行,得到dp[N-1]就是左上角到右下角的最小路径和。
代码实现:
int minPathSum2(int matrix[][col], int dp[])
{
dp[0] = matrix[0][0];
//计算第一行的最短路径
for(int j = 1; j < col; j++)
{
dp[j] = dp[j-1] + matrix[0][j];
}
//计算除了第一行的其它最小路径和
for(int i = 1; i < row; i++)
{
for(int j = 0; j < col; j++)
{
if(j == 0)
{
dp[j] += matrix[i][j];
}
else
{
dp[j] = dp[j-1] < dp[j] ? dp[j-1] : dp[j];
dp[j] += matrix[i][j];
}
}//for
}//for
return dp[col - 1];
}
这种二维动态规划的空间压缩几乎可以应用到所有的二维动态规划的题目中,通过一个数组(列数组或者航数组)滚动更新的方式节省了大量的空间。但是在滚动的过程中动态规划表不断的被行数组或者列数组覆盖更新,最后得到的仅仅是动态规划表的最后一行或者最后一列的最小路径和。所以真正的最小路径是不能通过动态规划表回溯得到的。