当前位置: 首页 > article >正文

代码随想录算法训练营第四十一天| 343 整数拆分 96 不同的二叉搜索树

代码随想录算法训练营第四十一天| 343 整数拆分 96 不同的二叉搜索树

LeetCode 343 整数拆分

题目链接: 343.整数拆分

动规五部曲,分析如下:

  • 确定dp数组(dp table)以及下标的含义

dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。

dp[i]的定义将贯彻整个解题过程,下面哪一步想不懂了,就想想dp[i]究竟表示的是啥!

  • 确定递推公式

可以从1遍历j,然后有两种渠道得到dp[i].

一个是j * (i - j) 直接相乘。

一个是j * dp[i - j],相当于拆分(i - j)

递推公式:dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});

  • dp的初始化

从dp[i]的定义来说,dp[0] dp[1] 不应该初始化,也就是没有意义的数值。

拆分0和拆分1的最大乘积是多少?这是无解的。

只初始化dp[2] = 1,从dp[i]的定义来说,拆分数字2,得到的最大乘积是1

  • 确定遍历顺序

确定遍历顺序,先来看看递归公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));

dp[i] 是依靠 dp[i - j]的状态,所以遍历i一定是从前向后遍历,先有dp[i - j]再有dp[i]。

所以遍历顺序为:

for (int i = 3; i <= n ; i++) {
    for (int j = 1; j < i - 1; j++) {
        dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
    }
}
  • 举例推导dp数组

整体代码:

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

LeetCode 96 不同的二叉搜索树

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

动规五部曲:

  • 确定dp数组(dp table)以及下标的含义

dp[i] : 1到i为节点组成的二叉搜索树的个数为dp[i]

可以理解是i个不同元素节点组成的二叉搜索树的个数为dp[i]

  • 确定递推公式

已经可以看出递推关系, dp[i] += dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量]

j相当于是头结点的元素,从1遍历到i为止。

递推公式:dp[i] += dp[j - 1] * dp[i - j]; ,j-1 为j为头结点左子树节点数量,i-j 为以j为头结点右子树节点数量

  • dp数组如何初始化

初始化,只需要初始化dp[0]就可以了,推导的基础是dp[0]。

从定义上来讲,空节点也是一棵二叉树,也是一棵二叉搜索树,这是可以说得通的。

从递归公式上来讲,dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量] 中以j为头结点左子树节点数量为0,也需要dp[以j为头结点左子树节点数量] = 1, 否则乘法的结果就都变成0了。

初始化dp[0] = 1

  • 确定遍历顺序

首先是遍历节点数,从递归公式:dp[i] += dp[j - 1] * dp[i - j]可以看出,节点数为i的状态是依靠 i之前节点数的状态。而遍历i里面每一个数作为头结点的状态,用j来遍历。

代码如下:

for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= i; j++) {
        dp[i] += dp[j - 1] * dp[i - j];
    }
}
  • 举例推导dp数组

整体代码:

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

http://www.kler.cn/a/3860.html

相关文章:

  • 电脑换固态硬盘
  • Qt QML专栏目录结构
  • 【数据分享】1929-2024年全球站点的逐日平均气温数据(Shp\Excel\免费获取)
  • Apache Hive--排序函数解析
  • 二叉搜索树(TreeMapTreeSet)
  • 25/1/15 嵌入式笔记 初学STM32F108
  • 铁威马NAS教程之利用docker快速搭建个人在线书库
  • 高规格国赛接棒AidLux AI应用竞赛,AidLux邀你来报名赢大奖!
  • 【百面成神】java web基础7问,你能坚持到第几问
  • java HashMap 源码分析(深度讲解)
  • 【Java版oj】day19汽水瓶、查找两个字符串a,b中的最长公共子串
  • 【MySQL】MySQL的介绍MySQL数据库及MySQL表的基本操作
  • 将一段数字转为字符串
  • HTB-Stocker
  • Java_Spring:6. Spring 整合 Junit
  • 杨辉三角形 (蓝桥杯) JAVA
  • 变量的理论分布模型
  • includes() 超全详细用法
  • C 语言网络编程 — 内核协议栈收包/发包流程
  • 大数据之Spark基础环境
  • MySQL数据库基础
  • 【学习经验分享NO.21】学习资料分享(持续更新)
  • USB组合设备——带鼠标功能的键盘
  • 常见的嵌入式微处理器(Micro Processor Unit,MPU)
  • 如何安装 Composer
  • CloudCompare 二次开发(6)——插件中拖拽添加Qt窗口(区域生长算法为例)