题目链接:62.不同路径、63. 不同路径 II、343. 整数拆分(提高)、96.不同的二叉搜索树(提高)
文章链接:代码随想录
动态规划
1. 不同路径
- 确定dp数组(dp table)以及下标的含义:dp[i][j] 表示从 (0, 0) 出发到 (i, j) 有 dp[i][j] 条不同的路径
- 确定递推公式:dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
- dp数组如何初始化:dp[i][0] 一定都是1,因为从 (0, 0) 到 (i, 0) 的路径只有1条,dp[0][j]同理,因此初始化代码为:
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;
//注意从(1,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];
}
};
2. 不同路径 II
- 确定dp数组(dp table)以及下标的含义:dp[i][j] 表示从 (0, 0) 出发到 (i, j) 有 dp[i][j] 条不同的路径
- 确定递推公式:dp[i][j] = dp[i - 1][j] + dp[i][j - 1](特例:如果当前位置是障碍,则应该保持初始状态为0)
- dp数组如何初始化:因为从 (0, 0) 到 (i, 0) 的路径只有1条,dp[i][0] 一定都是1。但当障碍存在时,障碍之后(包括障碍)都是走不到的位置,因此障碍及其之后的位置初始值应该仍为0,dp[0][j]同理:
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;
- 确定遍历顺序:根据递归公式,dp[i][j] 都是从其上方和左方推导而来,因此应该从上往下、从左往右遍历
- 举例推导dp数组:
//在“62.不同路径”的实现基础上,因为存在障碍,对递推公式和初始化部分都要做相应的修改
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
if(obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) return 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] == 0) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m - 1][n - 1];
}
};
3. 整数拆分(提高)
- 确定dp数组(dp table)以及下标的含义:拆分数字 i 可以得到的最大乘积为 dp[i]
- 确定递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
- dp数组如何初始化:根据 dp[i] 的定义,dp[0] 、dp[1] 的初始化值都没有意义,只初始化 dp[2] = 1
- 确定遍历顺序:根据递归公式,dp[i] 是依靠 dp[i - j] 的状态,所以遍历 i 一定是从前向后遍历,先有 dp[i - j] 再有 dp[i]
- 举例推导dp数组:
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n + 1);
dp[0] = 0;
dp[1] = 0;
dp[2] = 1;
for(int i = 3; i <= n; i++) {
for(int j = 1; j < i; j++) {
dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
}
}
return dp[n];
}
};
4. 不同的二叉搜索树和(提高)
(待更新...)
5. 阶段总结
(待更新...)
相关题目和后续提高: