二刷代码随想录训练营Day 34|力扣62.不同路径、63. 不同路径 II、343.整数拆分、96.不同的二叉搜索树

1.不同路径

代码随想录

视频讲解:动态规划中如何初始化很重要!| LeetCode:62.不同路径_哔哩哔哩_bilibili

代码:

cpp 复制代码
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];
    }
};

note:涉及到方法数,一般就是用加法。这里说只能往右或者往下走,因此就将左方和上方的方法数加起来就是所求。

dp数组的含义:到达(i,j)下标的方法数为dp[i][j]

递推公式:dp[i][j] = dp[i - 1][j] + dp[i][j - 1]

dp数组的初始化:因为需要上方和左方的元素来推导,所以我们要初始化第一行和第一列。由于dp数组的含义是方法数,那么这些初始化的值就都是1,因为只有一种方法------沿直线走。

遍历顺序:由于需要从挨着第一行第一列的元素开始推导,且一个元素的值依赖于它正下方的值和左方的值,因此要用正序遍历

2.不同路径2

代码随想录 (programmercarl.com)

视频讲解:动态规划,这次遇到障碍了| LeetCode:63. 不同路径 II_哔哩哔哩_bilibili

代码:

cpp 复制代码
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] == 1) continue;
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        return dp[m - 1][n - 1];
    }
};

note:这题要注意初始化的时候,如果有障碍,即使跳出循环,障碍以及其以后的元素的方法数都为0,以及在进行递推的时候,当出现障碍的时候,进行continue,跳过本次推导。

3.整数拆分

代码随想录

视频讲解:动态规划,本题关键在于理解递推公式!| LeetCode:343. 整数拆分_哔哩哔哩_bilibili

代码:

cpp 复制代码
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 / 2; j++){
                dp[i] = max(dp[i],max(j * dp[i - j],j * (i - j)));
            }
        }
        return dp[n];
    }
};

note:这里的核心思想是尽量把n拆成几个近似相等的数相乘。

dp数组的含义:和为i的几个元素的最大乘积为dp[i]

递推公式:i可以拆成两个数或者三个以及三个以上的数------dp[i] = max(dp[i],max(j * (i - j), j * dp( i - j))) 其中的dp[i]也参与了求最大值的过程中,是因为我们要把循环里的历史数也要加入其中找出最大值。

dp数组的初始化:dp[0] = 0 dp[1] = 0,是因为这两个本来就没法拆。没什么意义,为了不影响最大值的求得,直接初始化为0. dp[2] = 1,这个是按照定义来的。

遍历顺序:后面的元素依赖于前面元素的值------从左往右遍历

4.不同的二叉搜索树

代码随想录

视频讲解:动态规划找到子状态之间的关系很重要!| LeetCode:96.不同的二叉搜索树_哔哩哔哩_bilibili

代码:

cpp 复制代码
class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n + 1,0);
        dp[0] = 1;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= i; j++){
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        return dp[n];
    }
};

note:

dp数组的含义:有i个节点构成的二叉搜索树有dp[i]种

递推公式:dp[i] += dp[j - 1] * dp[i - j] 其实就是左右子树的种类乘积的累加。注意左右子树结点数之和为i -1 因为要留一个结点作为根结点。

dp数组的初始化:由于题上说节点数大于等于1,所以初始化dp[0]即可 dp[0] = 1,空结点也算一种,而且不会影响后面的推导

遍历顺序:后面的元素依赖于前面元素的值------从左往右遍历

相关推荐
daiyang123...2 分钟前
测试岗位应该学什么
数据结构
alphaTao6 分钟前
LeetCode 每日一题 2024/11/18-2024/11/24
算法·leetcode
我们的五年13 分钟前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
kitesxian15 分钟前
Leetcode448. 找到所有数组中消失的数字(HOT100)+Leetcode139. 单词拆分(HOT100)
数据结构·算法·leetcode
做人不要太理性40 分钟前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
程序员-King.1 小时前
2、桥接模式
c++·桥接模式
chnming19871 小时前
STL关联式容器之map
开发语言·c++
VertexGeek1 小时前
Rust学习(八):异常处理和宏编程:
学习·算法·rust
石小石Orz1 小时前
Three.js + AI:AI 算法生成 3D 萤火虫飞舞效果~
javascript·人工智能·算法
程序伍六七1 小时前
day16
开发语言·c++