代码随想录算法训练营29天 | ​​62.不同路径、63. 不同路径 II、343. 整数拆分(提高)、96.不同的二叉搜索树(提高)

题目链接:62.不同路径63. 不同路径 II343. 整数拆分(提高)96.不同的二叉搜索树(提高)
文章链接:代码随想录

动态规划


1. 不同路径

  1. 确定dp数组(dp table)以及下标的含义:dp[i][j] 表示从 (0, 0) 出发到 (i, j) 有 dp[i][j] 条不同的路径
  2. 确定递推公式:dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
  3. 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;
  4. 确定遍历顺序:根据递归公式,dp[i][j] 都是从其上方和左方推导而来,因此应该从上往下、从左往右遍历
  5. 举例推导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

  1. 确定dp数组(dp table)以及下标的含义:dp[i][j] 表示从 (0, 0) 出发到 (i, j) 有 dp[i][j] 条不同的路径
  2. 确定递推公式:dp[i][j] = dp[i - 1][j] + dp[i][j - 1](特例:如果当前位置是障碍,则应该保持初始状态为0)
  3. 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;
  4. 确定遍历顺序:根据递归公式,dp[i][j] 都是从其上方和左方推导而来,因此应该从上往下、从左往右遍历
  5. 举例推导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. 整数拆分(提高)

    1. 确定dp数组(dp table)以及下标的含义:拆分数字 i 可以得到的最大乘积为 dp[i]
    2. 确定递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
    3. dp数组如何初始化:根据 dp[i] 的定义,dp[0] 、dp[1] 的初始化值都没有意义,只初始化 dp[2] = 1
    4. 确定遍历顺序:根据递归公式,dp[i] 是依靠 dp[i - j] 的状态,所以遍历 i 一定是从前向后遍历,先有 dp[i - j] 再有 dp[i]
    5. 举例推导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. 阶段总结

    (待更新...)


     相关题目和后续提高:


    心得:

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值