题目链接:62.不同路径
一个机器人位于一个 m x n
网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
文章讲解/视频讲解:https://programmercarl.com/0062.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84.html
可以建立一个二维dp数组,二维数组中的每个值代表着到达当前下标有多少种不同路径。
首先是初始化,因为机器人只能够向下或向右移动,因此对于所有的i,dp[0][i]
都为1,对于所有的j,dp[j
][0]也都为1。
然后是遍历顺序,用两层循环来遍历,外层循环是从上到下,内层循环是从左到右进行遍历。
递推式为:dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
。
以示例1为例子,dp数组如下所示:
1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
1 | 3 | 6 | 10 | 15 | 21 | 28 |
正确。
另外,注意到dp数组横向的每一层可以直接取代上一层,而对其他元素没有影响,因此可以被压缩成一维的数组,这时递推式为:dp[j] = dp[j] + dp[j - 1]
。
初始化时dp[j]均为1。
// 原写法
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>>dp(m, vector<int>(n, 0));
for(int i = 0;i<m;i++) dp[i][0] = 1;
for(int j = 0;j<n;j++) dp[0][j] = 1;
for(int i = 1;i<m;i++){
for(int j = 1;j<n;j++){
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
};
// 将dp数组压缩成一维数组
class Solution {
public:
int uniquePaths(int m, int n) {
vector<int> dp(n, 1);
for(int i = 1;i<m;i++){
for(int j = 1;j<n;j++){
dp[j] = dp[j] + dp[j - 1];
}
}
return dp[n - 1];
}
};
题目链接:62.不同路径 II
一个机器人位于一个 m x n
网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1
和 0
来表示。
文章讲解/视频讲解:https://programmercarl.com/0063.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84II.html
建立一个二维的dp数组,其中每一个下标代表了到达当前位置有多少条不同的路径。
首先是初始化,对第一层和第一列进行初始赋值。在第一层,从左往右遍历,如果没有遇到石块,当前的dp[0][j] = 1
,如果遇到了石块,当前dp[0][j] = 0
,并且该层之后的每一项都为0。对第一列的赋值同理。因为机器人只能向下或向右移动,如果在第一层或第一列遇到了石块,那么第一层或第一列的其他位置都到达不了。
然后确定递推式:
如果(i,j)
这个位置是石块:dp[i][j] = 0;
否则:dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
遍历顺序同样是两层循环,外层是从上到下,内层是从左往右遍历。
与不同路径类似,这道题的dp数组也可以压缩成一维的,类似于滚动数组。
// 原写法
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size(), n = obstacleGrid[0].size();
vector<vector<int>> dp(m, vector<int>(n, 0));
for(int i = 0;i<m;i++){
if(obstacleGrid[i][0] == 1) break;
else dp[i][0] = 1;
}
for(int j = 0;j<n;j++){
if(obstacleGrid[0][j] == 1) break;
else dp[0][j] = 1;
}
for(int i = 1;i<m;i++){
for(int j = 1;j<n;j++){
if(obstacleGrid[i][j] == 1) dp[i][j] = 0;
else dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
};
// 滚动数组
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size(), n = obstacleGrid[0].size();
vector<int> dp(n, 0);
for(int j = 0;j<n;j++){
if(obstacleGrid[0][j] == 1) dp[j] = 0;
else if(j == 0) dp[j] = 1;
else dp[j] = dp[j - 1];
}
for(int i = 1;i<m;i++){
for(int j = 0;j<n;j++){
if(obstacleGrid[i][j] == 1) dp[j] = 0;
else if(j != 0) dp[j] = dp[j] + dp[j - 1];
}
}
return dp[n - 1];
}
};