62.不同路径
根据代码随想录算法训练营第三十八天中的动态规划五步骤来分析这道题目。题目问的是从左上角到右下角将会有多少条不同的路径?那么我们可以创建一个和m*n网格逻辑上等价的二维数组,行数为m,列数为n,每一个数组元素保存的是到达当前位置有多少种不同路径。
因为机器人走格子只能向右或者向下走,所以dp到达当前位置有多少种不同路径只能由当前数组元素上边和左边的值决定,联想到代码随想录算法训练营第三十八天问题的思路,不难想到当前位置的值是由正上方数组元素的值和正左方数组元素的值相加得到,于是递推公式
dp[j][i] = dp[j-1][i] + dp[j][i-1];
那么如何初始化,试设想,如果机器人从起点一直往右走,或者一直往下走,都只有一种走法,也就是说我们可以把第一行和第一列元素的值都初始化成1,因为这样初始化恰好也能满足递推公式的赋值。
本题是要遍历dp二维数组的,所以肯定需要两个for循环,先遍历行还是先遍历列在此题中并不关键,我认为两种遍历顺序在本题都是可取的,习惯上,我会选择先遍历行。
class Solution {
public:
int uniquePaths(int m, int n) {
int dp[m][n];
for(int i = 0 ; i < n ; i++){
dp[0][i] = 1;
}
for(int j = 0 ; j < m ; j++){
dp[j][0] = 1;
}
for(int j = 1; j < m; j++){
for(int i = 1; i < n ; i++){
dp[j][i] = dp[j-1][i] + dp[j][i-1];
}
}
return dp[m-1][n-1];
}
};
63. 不同路径 II
这道题目大体思路和上一道题目差不多,只是多了一个条件,就是网格中含有障碍物,如果dp数组元素的位置对应的网格的位置含有障碍物,应该如何操作?
其实应该很自然能想到,有障碍物表明此路不通,也就是没有路可以到达这个位置,于是就可以把这个位置赋值成0,再带入递推公式看看是否有问题?模拟一遍发现并没有什么问题,这个做法是成立的。
障碍物的限制条件影响到了两个过程,一个是初始化的过程,一个是递推的过程。
对于初始化来说,我们一开始的想法是一直向右走或者一直向下走,那如果这个过程中遇到障碍物怎么办?实际上,只要有一个位置有障碍物,之后的路线就走不下去了,也就是说,后面的dp数组元素的值都必须是0。
对于递推来说,遇到障碍物,dp数组元素赋值为0即可,因为不止一个方向可以到当前位置。
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
if(obstacleGrid[0][0] == 1)return 0;
int dp[obstacleGrid.size()][obstacleGrid[0].size()];
for(int i = 0 ; i < obstacleGrid[0].size() ; i++){
if(obstacleGrid[0][i] == 1){
while(i < obstacleGrid[0].size()){
dp[0][i++] = 0;
}
break;
}
dp[0][i] = 1;
}
for(int j = 0 ; j < obstacleGrid.size() ; j++){
if(obstacleGrid[j][0] == 1){
while(j < obstacleGrid.size()){
dp[j++][0] = 0;
}
break;
}
dp[j][0] = 1;
}
for(int j = 1; j < obstacleGrid.size(); j++){
for(int i = 1; i < obstacleGrid[0].size() ; i++){
if(obstacleGrid[j][i] == 1)dp[j][i] = 0;
else dp[j][i] = dp[j-1][i] + dp[j][i-1];
}
}
return dp[obstacleGrid.size()-1][obstacleGrid[0].size()-1];
}
};