题目1:Triangle
给出一个三角形,计算从三角形顶部到底部的最小路径和,每一步都可以移动到下面一行相邻的数字, 例如,给出的三角形如下:
[2],↵
[3,4],↵
[6,5,7],↵
[4,1,8,3]↵
最小的从顶部到底部的路径和是2 + 3 + 5 + 1 = 11。
注意:如果你能只用O(N)的额外的空间来完成这项工作的话,就可以得到附加分,其中N是三角形中的行总数。
从倒数第二行求起,动态转移方程:f(i , j) = min ( f( i + 1, j) , f(i + 1 , j + 1)) + f(i , j)
int minimumTotal(vector<vector<int> > &triangle)
{
for(int i = triangle.size() - 2;i >= 0;i--)
{
for(int j = 0;j < triangle[i].size();j++)
{
triangle[i][j] = min(triangle[i+1][j],triangle[i+1][j+1]) + triangle[i][j];
}
}
return triangle[0][0];
}
题目2:unique-paths
题目要求只能向右走或向下走,所以到达每一种格子的路径总数就是他的左边格子和上边格子到达路径数之和。
特殊情况:第一行和第一列分别没有上边格子和左边格子,所以到达他们的路径只能向右直走或向下直走,所以他们的路径总数总是为1。
动态转移方程:f ( i , j ) = f ( i , j - 1 ) + f ( i - 1,j )
int uniquePaths(int m, int n)
{
vector<vector<int>> v(m,vector<int>(n,1));
for(int i = 1;i <m;i++)
{
for(int j = 1;j<n;j++)
{
v[i][j] = v[i-1][j]+v[i][j-1];
}
}
return v[m-1][n-1];
}
题目3:unique-paths-ii
继续思考题目"Unique Paths": 如果在图中加入了一些障碍,有多少不同的路径? 分别用0和1代表空区域和障碍
例如
下图表示有一个障碍在3*3的图中央。
[0,0,0],↵
[0,1,0],↵
[0,0,0]↵
有2条不同的路径,备注:m和n不超过100.
以下面的图片为例:
1、先讨论特殊情况:第一行和第一列,我们发现,当第一行或第一列中有一个为1堵住时,后面的就会全部变成被堵住,因为第一行和第一列只有一条路径,他只能从左边或上边过来,前面的那条路都被挡住了,后面的自然就不能到达了。
2、下面看其他情况:当他的上边或左边是通路(为0)时就拿,为1就不拿。
f( i , j) —表示到达每个格子的路径数,g(i , j) —表示每个格子的状态(1代表不可通行,0代表通行)
动态转移方程:f ( i , j ) = f (i - 1 , j ) + f ( i , j - 1 ) && g(i - 1 , j ) == 0 && g(i , j - 1 ) == 0
int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid)
{
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
vector<vector<int>> path(m,vector<int>(n,0));//path保存到达每个格子的路径总数
for(int i =0;i<m;i++)//先处理特殊情况,第一行
{
if(obstacleGrid[i][0]==1)//如果状态为不可通行,后面的不用再管,默认到达路径总数为0
{
break;
}
else//如果可以通行,将到达路径总数置为1
{
path[i][0] = 1;
}
}
for(int i =0;i<n;i++)//第一列
{
if(obstacleGrid[0][i]==1)
{
break;
}
else
{
path[0][i] = 1;
}
}
for (int i = 1; i < m; i++)
{
for (int j = 1; j< n; j++)
{
if(obstacleGrid[i][j]==0)//如果这个格子可以通行,计算它的路径总数
{
//注意:这里不用管它的左边和右边是否可以通行,若果不可以通行,
//那么那个格子的路径到达数在之前已经置为0了,就算加上也无妨。
path[i][j] = path[i][j-1] +path[i-1][j];
}
else
{
path[i][j] = 0;
}
}
}
return path[m - 1][n - 1];//最后返回终点格子的路径到达数
}
题目4:Minimum Path Sum
给定一个由非负整数填充的m x n的二维数组,现在要从二维数组的左上角走到右下角,请找出路径上的所有数字之和最小的路径。 注意:你每次只能向下或向右移动。
方法1:递归
从最后一个格子开始,它的最小路径数就是左边和上边最小路径数中最小的再加上自己的路径。
动态转移方程:f ( i , j ) = min( f ( i - 1 , j ) + f ( i , j - 1) ) + f ( i , j )
int MinPath(vector<vector<int> > &grid, int n, int m)
{
if (n > 0 && m > 0)
{
return grid[n][m] + min(MinPath(grid, n - 1, m), MinPath(grid, n, m - 1));
}
else if (n == 0 && m == 0)
{
return grid[0][0];
}
else
{
if (n == 0)
{
return grid[n][m] + MinPath(grid, n, m - 1);
}
else
{
return grid[n][m] + MinPath(grid, n - 1, m);
}
}
}
int minPathSum(vector<vector<int> > &grid)
{
return MinPath(grid, grid.size() - 1, grid[0].size() - 1);
}
注意:递归的方法理解起来更容易些,但是在数据量稍大就可能会导致栈溢出,在牛客网上也编不过。
方法2:顺序遍历
有题目2,3的基础,我们知道,第一行和第一列是特殊情况,先要处理。
minpath[i][j] —代表每个格子的最小路径
1、对于第一行和第一列的动态转移方程:
第一行:
minpath [i] [j] = minpath [i] [j] + minpath [i] [j-1]
第一列:
minpath [i] [j] = minpath [i] [j] + minpath [i-1] [j]
2、其他格子的动态转移方程:
minpath [i] [j] = min(minpath [i] [j-1] + minpath [i-1] [j] ) + minpath [i] [j]
int minPathSum(vector<vector<int> > &grid)
{
int n = grid.size();
int m = grid[0].size();
for(int i = 1;i<n;i++)
{
grid[i][0] += grid[i-1][0];
}
for(int i = 1;i<m;i++)
{
grid[0][i] += grid[0][i-1];
}
for(int i = 1;i<n;i++)
{
for(int j = 1;j<m;j++)
{
grid[i][j] += min(grid[i][j-1],grid[i-1][j]);
}
}
return grid[n-1][m-1];
}