算法第29天|动态规划dp2:不同路径、不同路径Ⅱ、整数拆分、不同的二叉搜索树

今日总结:

1、动态规划的五部曲:

(1)确定动态规划数组dp[]的含义,确定dp[]数组的下标的含义

(2)确定动态规划的递推公式

(3)确定动态规划的初始化条件

(4)确定动态规划的传播方向

(5)举例论证递推公式的正确

2、不同路径Ⅱ(需要重新思考)

要注意障碍所在的多种位置:第一行第一列、起点终点、普通中间网格

3、整数拆分(需要重新思考)

注意对于整数差分获得乘积的最大的几种情况

1、拆分成两个后的乘积就是最大值

2、拆分成两个后,还需要对第二个数进行拆分

遍历的时候,其实将j遍历到i/2即可,因为剩余的已经相当于遍历过了

不同路径

题目链接:62. 不同路径 - 力扣(LeetCode)

代码随想录

整体思路:

从左上到右下:所有的位置(i,j)只能通过向下移动、向右移动,进行到达,所以位置(i.j)与之前状态(i-1,j),(i,j-1)相关,是动态规划的问题。

1、确定动态规划的dp数组含义以及下标含义

dp[i][j]的含义是到达当前位置有多少条路径

i是横坐标,j是纵坐标

2、确定动态规划的递推公式(状态转移方程)

dp[i][j] = dp[i-1][j]+dp[i][j-1]

3、确定动态规划的初始化条件

可以通过图分析可知,在第一行第一列,都是一种路径

4、确定动态规划的方向:

从左向右,从上到下

5、举例论证

简单无需举例

整体代码:

cpp 复制代码
class Solution {
public:
    int uniquePaths(int m, int n) {
        /*
        1、确定动态规划的dp数组含义以及下标含义
                dp[i][j]的含义是到达当前位置有多少条路径
                i是横坐标,j是纵坐标
        2、确定动态规划的递推公式(状态转移方程)
                dp[i][j] = dp[i-1][j]+dp[i][j-1]
        3、确定动态规划的初始化条件
                可以通过图分析可知,在第一行第一列,都是一种路径
        4、确定动态规划的方向
                左向右,从上到下
        5、举例论证
                简单无需举例*/
    vector<vector<int>>dp(m,vector<int>(n,0));
    //遍历dp
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==0||j==0)
            {
                dp[i][j]=1;
            }
            else
            {
                dp[i][j] = dp[i-1][j] +dp[i][j-1];
            }
        }
    }
    return dp[m-1][n-1];
        
    }
};

不同路径Ⅱ

题目链接:63. 不同路径 II - 力扣(LeetCode)

代码随想录

整体思路:

与上一个题类似,需要注意有障碍物

1、障碍物在开始或者终点-->直接返回0

2、障碍物在第一行、第一列,障碍物之后的位置(包含障碍物坐标)路径全部为0

3、障碍物在中间的网格,该点的路径为0

(没进行代码优化,但是结果正确)

整体代码:

cpp 复制代码
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        vector<vector<int>>dp(obstacleGrid.size(),vector<int>(obstacleGrid[0].size(),0));//定义dp数组
        //初始化
        //1、注意障碍物在起点、终点的情况
        if(obstacleGrid[0][0]==1||obstacleGrid[obstacleGrid.size()-1][obstacleGrid[0].size()-1]==1)return 0;
        //注意第一行、第一列正常应该是一条路径,但是如果出现了障碍,后边的网格的路径为0
        for(int i=0;i<obstacleGrid.size();i++)//遍历行,所以是第一列
        {
            if(obstacleGrid[i][0]==0)
            {
                dp[i][0] =1;
            }
            else if(obstacleGrid[i][0]==1)break;
        }
        for(int j=0;j<obstacleGrid[0].size();j++)
        {
            if(obstacleGrid[0][j]==0)
            {
                dp[0][j]=1;
            }
            else if(obstacleGrid[0][j]==1)
            {
                break;
            }
        }
        //遍历整个网格,从第二行第二列开始就行,因为第一行第一列初始化了
        for(int i=1;i<obstacleGrid.size();i++)
        {
            for(int j=1;j<obstacleGrid[0].size();j++)
            {
                if(obstacleGrid[i][j]==0)//说明不是障碍物
                {
                    dp[i][j] = dp[i-1][j]+dp[i][j-1];
                }
                else if(obstacleGrid[i][j]==0)//可不写
                {
                    dp[i][j] = 0;
                }
            }
        }
        return dp[obstacleGrid.size()-1][obstacleGrid[0].size()-1];//0,1
    }
};

整数拆分

题目链接:343. 整数拆分 - 力扣(LeetCode)

代码随想录

整体思路:

目标:拆分的整数的乘积最大化

dp数组的作用是将当前的元素与之前的状态相联系,

从1遍历到n,相当于拆分,将当前的拆分值与剩余值进行相乘,

n=10

j=1,j*9;对于9还可以继续拆,所以需要找到9的最大的拆分乘积进行记录

j=2,j*8,对于8还可以继续拆,所以需要找到8的最大的查拆乘积分进行记录

。。。

所以,对于一个数进行拆分,需要知道这个数之前的所有数的最大拆分,然后找到最大的值-->当前元素的值与之前元素的状态有关,可以使用动态规划dp

(1)确定dp数组的含义、下标的含义

dp数组表示当前数的最大拆分的乘积,下标表示当前元素

(2)确定dp数组的迭代公式(状态转移方程)

dp[i] = j*dp[i-j];dp[i-j]表示的是dp[i-j]的最大拆分乘积,之所以不需要对j进行拆分是因为j是遍历元素,所有的拆分项都在dp[i-j]中出现过

同时要注意,dp[i]的获取还有一种情况,就是i-j本身就是最大值无需在进行拆分dp[i-j]

dp[i] = max(dp[i],dp[i-j],(i-j)*j),

(3)确定dp数组的初始化

dp[0]=0,dp[1]=1,dp[2]=2;

(4)确定dp数组的方向

从小到n

(5)举例论证

无需举例

整体代码:

cpp 复制代码
class Solution {
public:
    int integerBreak(int n) {
        //谨记dp数组表示当前元素的最大乘积,下标表示当前数组
        vector<int>dp(n+1,0);//注意要处理的是n而不是n-1
        dp[0]=0,dp[1]=1;
        for(int i=2;i<=n;i++)//遍历所有的dp数组
        {
            for(int j=1;j<i;j++)//通过遍历从0-i确定当前的最大dp[i]
            {
                //dp状态转移方程
                dp[i] = max(dp[i],max(j*dp[i-j],(i-j)*j));
            }
        }
        return dp[n];
    }
};

不同的二叉搜索树

题目链接:96. 不同的二叉搜索树 - 力扣(LeetCode)

代码随想录

整体思路:

整体代码:

相关推荐
菜鸟555554 分钟前
常用算法思想及模板
算法·dp·模板·分治·竞赛·算法思想
肆佰.6 分钟前
c++ 派生类
数据结构·c++·算法
醉卧红尘的鱼21 分钟前
最优估计准则与方法(5)加权最小二乘估计(WLS)_学习笔记
学习·算法
她说人狗殊途28 分钟前
Map 集合
java·开发语言·算法
leafpipi1 小时前
【机器学习】pycharm使用SSH SFTP 远程连接 ubuntu服务器 进行开发+调试+数据训练
服务器·学习·算法·ubuntu·pycharm·ssh
姜不吃葱1 小时前
【力扣热题100】哈希——最长连续序列
算法·leetcode·哈希算法
百度Geek说1 小时前
直击WAIC | 百度袁佛玉:加速具身智能技术及产品研发,助力场景应用多样化落地
算法
Dovis(誓平步青云)1 小时前
《C++二叉搜索树原理剖析:从原理到高效实现教学》
开发语言·c++·算法·二叉搜索树·原理剖析
kanhaoning2 小时前
用KL散度将Qwen3-8B向量模型知识蒸馏给小模型BGE-m3
算法
啊阿狸不会拉杆2 小时前
《Java 程序设计》第 12 章 - 异常处理
java·开发语言·jvm·python·算法·intellij-idea