leetcode 62. 不同路径
题目链接:不同路径
- 确定dp数组以及下标的含义
dp[i][j]
:表示从(0 ,0)出发,到(i, j) 有dp[i][j]
条不同的路径 - 确定递推公式
求dp[i][j]
,只能有两个方向推导出来,即dp[i - 1][j]
和dp[i][j - 1]
所以dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
- dp数组的初始化
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
- 确定遍历顺序
dp[i][j]
是从上方和左方推导而来,所以遍历顺序从左到右一层一层遍历。 - 举例推导dp数组
版本一:
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];}
};
时间复杂度:O(m × n)
空间复杂度:O(m × n)
版本二
节约空间,可以直接使用一维数组(滚动数组)。
class Solution {
public:int uniquePaths(int m, int n) {vector<int> dp(n);for (int i = 0; i < n; i++) dp[i] = 1;for (int j = 1; j < m; j++) {for (int i = 1; i < n; i++) {dp[i] += dp[i - 1];}}return dp[n - 1];}
};
时间复杂度:O(m × n)
空间复杂度:O(n)
leetcode 63. 不同路径||
题目链接:不同路径||
leetcode 62.不同路径 中详细分析了没有障碍的情况,有障碍情况就是标记对应的dp数组保持初始值(0)。
- 确定dp数组以及下标的含义
dp[i][j]
:表示从(0 ,0)出发,到(i, j) 有dp[i][j]
条不同的路径 - 确定递推公式
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
考虑障碍:
if (obstacleGrid[i][j] == 0) { // 当(i, j)没有障碍的时候,再推导dp[i][j]dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
- dp数组的初始化
如果(i, 0)
这条边有了障碍之后,障碍之后(包括障碍)都是走不到的位置,所以障碍之后的
dp[i][0]
都为0
vector<vector<int>> dp(m, vector<int>(n, 0)); //遇到障碍后的位置都为0
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
- 确定遍历顺序
dp[i][j]
是从上方和左方推导而来,所以遍历顺序从左到右一层一层遍历。 - 举例推导dp数组
版本一:
class Solution {
public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int m = obstacleGrid.size();int n = obstacleGrid[0].size();if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1) //如果在起点或终点出现了障碍,直接返回0return 0;vector<vector<int>> dp(m, vector<int>(n, 0));for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {if (obstacleGrid[i][j] == 1) continue;dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}return dp[m - 1][n - 1];}
};
时间复杂度:O(n × m),n、m 分别为obstacleGrid 长度和宽度
空间复杂度:O(n × m)
版本二:
空间优化版本:
class Solution {
public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {if (obstacleGrid[0][0] == 1)return 0;vector<int> dp(obstacleGrid[0].size());for (int j = 0; j < dp.size(); ++j)if (obstacleGrid[0][j] == 1)dp[j] = 0;else if (j == 0)dp[j] = 1;elsedp[j] = dp[j-1];for (int i = 1; i < obstacleGrid.size(); ++i)for (int j = 0; j < dp.size(); ++j){if (obstacleGrid[i][j] == 1)dp[j] = 0;else if (j != 0)dp[j] = dp[j] + dp[j-1];}return dp.back();}
};
时间复杂度:O(n × m),n、m 分别为obstacleGrid 长度和宽度
空间复杂度:O(m)