开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情
路径问题容易可视化,我们可以观察动态规划的转移过程了解到最佳路径是如何被选择
题目描述
一个机器人位于一个 m x n 网格的左上角,机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。问总共有多少条不同的路径?
思路分析
由于只能向下或者向右走,那么当前的路径数=上面节点的路径数+左面节点的路径数,定义二维数组dp[i][j]记录各节点到起点的路径数
- 只能向右走时:dp[i][j]=dp[i][j-1]
- 只能向下走时: dp[i][j]=dp[i-1][j]
- 既能向右又能向下时:dp[i][j]=dp[i][j-1]+dp[i-1][j]
代码实现
class Solution {
public:
int uniquePaths(int m, int n) {
//当i=m-1时(最后一行),不能向下
//当j=n-1时(最后一列),不能向右
//dp[i][j]代表从初始节点到当前节点的路径数
//dp[i][i]=初始节点到当前节点所在行的前一个节点的路径数+初始节点到当前节点所在列的前一个节点的路径数
vector<vector<int>> dp(m, vector<int>(n, 1));
for(int i=1;i<m;i++)
for(int j=1;j<n;j++){
dp[i][j]=dp[i][j-1]+dp[i-1][j];
}
return dp[m-1][n-1];
}
};
不同路径题目变式,即有障碍物时
同上一题,当考虑网格中有障碍物,应如何计算路径数?网格数组中,有障碍物值为1,没有障碍物值为0.
思路分析
此时要进行情况分析;
- 起点和终点只要有一个有障碍物,就没有从起点到终点的路径数
- 在网格中访问时,分为四种情况:
- 访问起点(此时进行路径数目初始化)
- 访问第一列和第一行以外的节点,此时路径数目能访问节点左侧+上侧
- 访问第一列的节点,此时路径数目只能访问上侧
- 访问第一行的节点,此时路径数目只能访问左侧
- 在访问某节点时分为当前节点有障碍物和没有障碍物两种情况
代码描述
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
//获取表格的行和列
int row=obstacleGrid.size(),col=obstacleGrid[0].size();
//定义一个二维数组存储初始节点到此节点的路径数目
vector<vector<int>> dp(row, vector<int>(col, 1));
//判断起点和终点是否有障碍物,只要有一个有障碍物,就不能从起点到达终点
if(obstacleGrid[0][0]==1||obstacleGrid[row-1][col-1]==1) return 0;
//当起点和终点都没有障碍物时(因为起点和终点只要有障碍物就会在上面的语句中返回,不会进行到这一步)
for(int i=0;i<row;i++){
for(int j=0;j<col;j++)
{
//给第一个节点初始化,只有一个节点时路径数是1
if(i==0&&j==0) dp[i][j]=1;
//因为if...else if..片段中只能执行一个语句,此时代表i>0||j>0
//当前节点有障碍物,因为此点不能过,则当前节点的路径数=0
else if(obstacleGrid[i][j]==1) dp[i][j]=0;
//此时(i>0||j>0)&&当前节点没有障碍物
//当不是第一列和第一行时
else if(i>0&&j>0) dp[i][j]=dp[i][j-1]+dp[i-1][j];
//此时不是第一行,但是是第一列,此时只能加上面一节点的路径数
else if(i>0)
dp[i][j]=dp[i-1][j];
//第一行,但是不是第一列,此时只能加上左边的路径数
else if(j>0)
dp[i][j]=dp[i][j-1];
}
}
//输出终点的路径数即可
return dp[row-1][col-1];
}
};