问题
思路
动态规划的本质还是分治那一套,上来先划分子问题。然后考虑原问题与子问题的关系,是不是有最有子结构,是不是有重叠子问题的性质。从而进一步判断是否用动态规划。
1. 状态定义:
dp[i][j]代表从左上方走到位置[i,j]的最小路径和
2. 转移函数:
dp[i][j]=min(dp[i−1][j],dp[i][j−1])(1)
3. 初始化:第一行第一列,因为他们只能来自于左侧和上方。
4. 打表
这个题和三角形最短路径的题目本质时一个题。换了个图形罢了。
代码(c)
int minPathSum(int** grid, int gridRowSize, int gridColSize) {
if(!grid || gridRowSize < 0 || gridColSize < 0)
return -1;
int** dp = (int*)malloc( gridRowSize * sizeof(int*) );
if(!dp)
return -1;
for( int i = 0; i < gridRowSize; ++i )
{
dp[i] = (int)malloc( gridColSize * sizeof(int) );
if( !dp[i] )
return -1;
}
dp[0][0] = grid[0][0];
for( int i = 1; i < gridColSize; ++i )
dp[0][i] = dp[0][i-1] + grid[0][i];
for( int i = 1; i < gridRowSize; ++i )
dp[i][0] = dp[i-1][0] + grid[i][0];
for( int i = 1; i < gridRowSize; ++i )
{
for( int j = 1; j < gridColSize; ++j )
{
dp[i][j] = ( dp[i-1][j] < dp[i][j-1] )?dp[i-1][j] + grid[i][j]:dp[i][j-1] + grid[i][j];
}
}
int ans = dp[gridRowSize - 1][gridColSize - 1];
for( int i = 0; i < gridRowSize; ++i )
{
free(dp[i]);
}
free(dp);
return ans;
}
代码(c++)
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if(!grid.size())
return 0;
int m = grid.size();
int n = grid[0].size();
// 状态定义 - dp[i][j]表示从[0,0]到[i,j]的最短路径
std::vector< std::vector<int> > dp( m, std::vector<int>( n, int() ) );
// 初始化
dp[0][0] = grid[0][0];
for( int i = 1; i < m; ++i ){
dp[i][0] = grid[i][0] + dp[i-1][0];
}
for( int i = 1; i < n; ++i ){
dp[0][i] = dp[0][i-1] + grid[0][i];
}
// 状态转移
for( int i = 1; i < m; ++i ){
for( int j = 1; j < n; ++j )
{
dp[i][j] = grid[i][j] + min( dp[i-1][j], dp[i][j-1] );
}
}
// 返回结果
return dp[m-1][n-1];
}
};
思路1(搜索)
当然,最朴素的办法,搜索一遍即可。结果也是显然的TLE。
代码1
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if(!grid.size()) return 0;
else return dfs( grid.size()-1, grid[0].size()-1, grid );
}
private:
// dfs(i,j)从[0,0]到[i,j]的最短路径
int dfs( int i, int j, vector<vector<int>>& grid){
if(!i&&!j)
return grid[0][0];
else if(!i)
return grid[i][j] + dfs(i, j - 1, grid);
else if(!j)
return grid[i][j] + dfs(i-1, j, grid);
else
return grid[i][j] + min( dfs(i,j-1, grid), dfs(i-1, j, grid) );
}
};
思路2(记忆化搜索)
对于上面的代码做修正,增加记忆化的过程。
代码2
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if(!grid.size()) return 0;
std::vector< std::vector<int> > dp( grid.size(), std::vector<int>(grid[0].size(), 0) );
return dfs( grid.size()-1, grid[0].size()-1, grid, dp );
}
private:
// dfs(i,j)从[0,0]到[i,j]的最短路径
int dfs( int i, int j, vector<vector<int>>& grid, vector<vector<int>>& dp){
// 有记忆
if( dp[i][j] > 0 )
return dp[i][j];
// 无记忆 - 记忆化搜索
if(!i&&!j)
return dp[i][j] = grid[i][j];
else if(!i)
return dp[i][j] = (grid[i][j] + dfs(i, j - 1, grid, dp));
else if(!j)
return dp[i][j] = (grid[i][j] + dfs(i-1, j, grid, dp));
else
return dp[i][j] = (grid[i][j] + min( dfs(i,j-1, grid, dp), dfs(i-1, j, grid, dp)));
}
};