代码随想录训练营第41天|LeetCode 343. 整数拆分、 96.不同的二叉搜索树
创始人
2024-03-19 06:17:44
0

参考

代码随想录

题目一:LeetCode 343.整数拆分

  1. 确定dp数组及其下标的含义
    dp[i]为整数i拆分后得到的最大化乘积。
  2. 确定递推公式
    dp[i]可以有两种方式得到:
  • dp[i] = j * (i-j),即只拆分成两个数,其中1 <= j <= i/2,最终dp[i]应该是所有j取值得到dp[i]中的最大值
  • dp[i] = j * dp[i-j],这种情况相当于将整数i拆分成多个数,因为其中的dp[i-j]已经被拆分过了,至少被拆分成两个数,具体拆分成多少个数不用去管,其中1 <= j <= i/2,同样dp[i]也是所有取值中的最大值。

在具体的代码实现上,dp[i] = max(dp[i],j * (i - j),j * dp[i - j]),这样对于每个i,只需要遍历一遍j就可以得到dp[i]了。把dp[i]放到max函数中的目的就是不断更新最大值。

  1. 初始化dp数组
    i = 0或1时,dp[i]是用不到的,所以不需要初始化只需要将dp[2]初始化为1,即dp[2] = 1

  2. 确定遍历顺序
    对于i,dp[i]需要由dp[i-j]来确定,所以i应该从小到大遍历;对于j,既可以从大到小也可以从小到大。

  3. 举例推导dp数组
    以n = 10为例,根据下面的递推公式进行推导:

dp[i] = max(dp[i],j * (i - j),j * dp[i - j]),其中3 <= i <= 10,1 <= j <= i/2

推导得到的dp数组为[1,2,4,6,9,12,18,27,36](注意下标从2开始),因此dp[10] = 36。

具体的代码实现如下:

class Solution {
public:int integerBreak(int n) {vector dp(n+1);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 * (i - j), j * dp[i - j]));return dp[n];}
};

题目二:LeetCode 96.不同的二叉搜索树

在这里插入图片描述
在这里插入图片描述
感觉这个题更像是找规律的题目,但是这个规律很难看出来。
dp[3]就是元素1为头结点搜索树的数量 + 元素2为头结点搜索树的数量 + 元素3为头结点搜索树的数量

元素1为头结点搜索树的数量 = 右子树有2个元素的搜索树数量 * 左子树有0个元素的搜索树数量

元素2为头结点搜索树的数量 = 右子树有1个元素的搜索树数量 * 左子树有1个元素的搜索树数量

元素3为头结点搜索树的数量 = 右子树有0个元素的搜索树数量 * 左子树有2个元素的搜索树数量

有2个元素的搜索树数量就是dp[2]。

有1个元素的搜索树数量就是dp[1]。

有0个元素的搜索树数量就是dp[0]。

所以dp[3] = dp[2] * dp[0] + dp[1] * dp[1] + dp[0] * dp[2]

  1. 确定dp数组(dp table)以及下标的含义
    dp[i] : 1到i为节点组成的二叉搜索树的个数为dp[i]。
  2. 确定递推公式
    dp[i] += dp[j - 1] * dp[i - j]; ,j-1 为j为头结点左子树节点数量,i-j 为以j为头结点右子树节点数量
  3. dp数组如何初始化
    初始化,只需要初始化dp[0]就可以了,推导的基础,都是dp[0]。根据递推公式,dp[0] = 1.
  4. 确定遍历顺序
    首先一定是遍历节点数,从递归公式:dp[i] += dp[j - 1] * dp[i - j]可以看出,节点数为i的状态是依靠 i之前节点数的状态。那么遍历i里面每一个数作为头结点的状态,用j来遍历。
  5. 举例推导dp数组
    当 n = 5时,dp数组为[1,1,2,5,14,42]

整体代码实现如下:

class Solution {
public:int numTrees(int n) {vector dp(n + 1);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];}
};

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...