二刷代码随想录训练营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,空结点也算一种,而且不会影响后面的推导

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

相关推荐
X同学的开始29 分钟前
数据结构之二叉树遍历
数据结构
limingade2 小时前
手机实时提取SIM卡打电话的信令和声音-新的篇章(一、可行的方案探讨)
物联网·算法·智能手机·数据分析·信息与通信
AIAdvocate4 小时前
Pandas_数据结构详解
数据结构·python·pandas
jiao000014 小时前
数据结构——队列
c语言·数据结构·算法
kaneki_lh4 小时前
数据结构 - 栈
数据结构
铁匠匠匠4 小时前
从零开始学数据结构系列之第六章《排序简介》
c语言·数据结构·经验分享·笔记·学习·开源·课程设计
C-SDN花园GGbond4 小时前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法
迷迭所归处5 小时前
C++ —— 关于vector
开发语言·c++·算法
leon6256 小时前
优化算法(一)—遗传算法(Genetic Algorithm)附MATLAB程序
开发语言·算法·matlab
CV工程师小林6 小时前
【算法】BFS 系列之边权为 1 的最短路问题
数据结构·c++·算法·leetcode·宽度优先