题目:给定一个矩阵,从左上角开始每次只能向右或者向下移动,最后到达右下角的位置,路径上的全部的数字累加起来做为这条路径的路劲和。要求返回全部路径和中的最小路径和。数组
举例:blog
路径1,3,1,0,6,1,0是全部路径中路径和最小的,因此返回其和12。io
解析:class
这个题目很相似以前的那个动态规划的数字三角的问题。毫无疑问的,这个问题也是用动态规划解决。只要肯定了状态和转移方程,这个题目很容易解决。下面直接给出代码:方法
//利用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上存储这个最短路径是哪一个点过来的。这样就能在找到最短路径和的同时,把路径一块找到。im
上面的题目很简单,不是这篇文章的重点,下面来看一下二维动态规划的空间压缩问题。上面的动态规划的时间复杂度是O(M*N),空间复杂度就是二维数组的大小O(M*N)。空间压缩的方法是不用记录全部的子问题的解。因此就能够只用一个行数组记录第一行、第二行...一次计算。直到最后一行,获得dp[N-1]就是左上角到右下角的最小路径和。二维数组
代码实现:db
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]; }
这种二维动态规划的空间压缩几乎能够应用到全部的二维动态规划的题目中,经过一个数组(列数组或者航数组)滚动更新的方式节省了大量的空间。可是在滚动的过程当中动态规划表不断的被行数组或者列数组覆盖更新,最后获得的仅仅是动态规划表的最后一行或者最后一列的最小路径和。因此真正的最小路径是不能经过动态规划表回溯获得的。img