【算法练习Day34】整数拆分不同的二叉搜索树

news2024/12/27 9:37:29

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:练题
🎯长路漫漫浩浩,万事皆有期待

文章目录

  • 整数拆分
  • 不同的二叉搜索树
  • 总结:

本期的两道题都有一些难度,不同的是第一道题看着可能有点想法,但是就是感觉差一点思路,以及代码不好实现,第二道题压根没什么思路,想不到它到底和动态规划的关系在哪,这是我对于初次做这两道题时候的想法。

整数拆分

343. 整数拆分 - 力扣(LeetCode)
在这里插入图片描述

整数拆分在leetcode上是一道中等难度的题,它的题目大意是将给定整数n拆解成若干数字乘积的形式,然后求出这些乘积中最大的一项是多少。我们首先要保证拆解出来的数字相加和应当等于原来的整数n。起初在做题的时候,我仅能想到用一个dp数组,且数组内部存取的应当是某个数字的最大乘积,进而一步步推出n的最大乘积,但是剩余的部分想不明白。我们来一起看看题解的解释,根据题解的思路来一步步推出。

dp数组的含义:dp数组含义之前已经说过了,它实际上就是求出第i个数字能够分解出来的数的乘积的最大值。

递推公式:这道题是将一个数字n分解成若干数字然后求最大乘积的题,那么有人就要问了那我们为什么还要用数组保存1-n的全部数字的整数拆分呢?关键点就在这里,我们要将该数分解,就要知道我们是怎么分解的,一个数可以被分解为j*(i-j),j是从1到i的数,例如说分解4,我们可以将其分解为:14,22,31,41,这么四种,也就是刚才的那个公式,j在循环里不断地增大,这样我么就可以使其算式发生变化。那么之前也说过,不一定将n这个整数分解成两个数相乘的形式,只要分解出的数相加等于n那么可以一直分解,例如10这个数我们可以分解为334,这也是合法的,那如果分解成这样我们要如何表示呢?这也是很重要的一点,我们可以想象334是由4乘上9得到的,根据dp数组的记忆我们可以写成是4*dp【9】,这是没毛病的,因为dp数组的定义就是某个数能被拆分后的最大乘积值,所以我们可以根据用dp数组来完成对于多个数字的拆分。

关于j的拆分

我们之前的上面写的公式都是假定j是根据循环变化而变化的值,而不是在递推公式里直接参与拆分的,那我们是否会落下一些情况呢?实际上并不会,每一次的j的变化而引起的数字拆分,是由上向下产生影响的!例如说10可以拆分为22222,那除了第一个2代表j之外,其余的2也可以分成11,但是不要忘记,第一个2也就是j的位置,早在前面j=1时候已经被拆成过11了,所以我们完全不要担心,后面能举出的j的拆分实例,均在j变得更小的时候,完成过类似于拆分的乘积运算了。

下一个我们需要在意的点是,由于递推公式写在j的变化之时,所以dp【i】是一定会随着j而改变的,那如果dp【i】之前已经找到了最大的值,我们还让他不停赋新值,不是会错过了吗,所以我们取一个最大值,即在dp【i】和j*(i-j)和j*dp【i-j}这三个值之中,取出最大值赋给dp【i】以达到保存更新最大值的效用。

dp数组的初始化:初始化就是dp【2】=2,为什么要这么写?因为0和1不能拆分,0就不用说了,1无法拆分成两个整数的相加。

遍历顺序:递推公式就可以得知了,我们推出当前的数字i的最大乘积,完全依赖于之前的数字,所以我们要从前向后遍历。

class Solution {
public:
    int integerBreak(int n) {
        vector<int>dp(n+1,0);
        dp[2]=1;
        for(int i=3;i<=n;i++){
            for(int j=1;j<i;j++)
            dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]));//dp[i-j]就相当于对i-j的拆分了
        }
        return dp[n];
    }
};

代码还是很简单的,但是想出思路要注意的点,还是蛮多的。

拆分的策略实际上就是固定前面的数字j,不拆分j而通过对于j的增加,而改变后面要拆分的值的策略。

不同的二叉搜索树

96. 不同的二叉搜索树 - 力扣(LeetCode)
在这里插入图片描述

这道题是很难的,可以说是困难题了。首先一定要审好题,这是一个求不同的二叉搜索树的题,是二叉搜索树而不是别的什么,强调这一点,是因为二叉搜索树是有一定的规律的。

这道题为什么说它难呢?递推公式比上一道题还难想,我们是根据分别列出n=1,n=2和n=3三种情况的二叉搜索树的形状,来找出一定的规律。n=1只有一种情况就是一个节点,n=2是一个八字形,即1开头的话那么就是有右子树2,2开头的话就是有一个左子树1,没有其他情况!因为这是搜索树,要严格按照搜索树的特点。n=3就分为1开头2开头和3开头三种情况,其中画图可知1和3开头的情况是和n=2的情况是一样的,两个八字形,而n以2开头是和n=1情况一样,是左右子树都平均的情况。这样算下来确实和题目案例对上了,n=3时候有五种情况,而这里我们是考虑二叉树的形状,而非二叉树节点值的不同,所以我们将n=3的以各个数字开头的情况和n=1和n=2的情况做了类比。

dp数组的含义:这里我们明确dp数组的含义实际上是用来保存数值i有多少种不同的二叉树。

递推公式

我们在上面已经分析了很多了,这里再来好好的看看递推公式的规律。 n=3的情况就是元素以1开头情况加上以2开头加上以3开头的情况。

而以1开头数量实际上等于右子树的有两个元素的情况*左子树有0个元素都情况

以2开头的数量等于右子树有一个元素的情况*左子树有1个元素的情况

以3开头的数量等于右子树有0个元素的情况*左子树有两个元素的情况

那么为什么是以乘法的形式得出的呢?而不是加法?我们假设左子树有五种元素情况,右子树有十种,那是不是左子树的每一种和右子树的十种都可以构造出不同的情况呢?所以我们这里用的公式就一定是乘法。

而有两个元素的情况就是n=2,也就是dp【2】,有1个就是dp【1】,0个就是dp【0】(这里看不懂,需要回想dp数组的含义是什么)

知道了这样的一个规律后,我们就可以推出dp【i】+=dp【j-1】*dp【i-j】

j-1是求左子树,i-j是求右子树,这里如果想不明白可以用n=3的各种情况带入,就能证明该公式一定是对的,那么为什么是+=而不是等于呢?这是因为我们要将各个情况都加进去,也就是1-n的所有开头情况加在一起,才是为n时的总二叉树个数。

dp初始化:dp的初始化就仅仅将dp【0】=1就可以了。0个节点也属于一种二叉树的情况。根据0

进而推出1,2,3等等。

遍历顺序:很明显也是一道从前往后遍历,因为要知道前面的情况才能得出n的情况。

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];
    }
};

这就是本题的代码了。虽然本题代码很简短,但是代码很难想出。

首先能想到用动态规划做就有点难度,其次是规律十分难找,我们要能想出用前面的情况推出此时以1-n开头的各顶点情况能与之前的1到n-1的各种情况相呼应是很难的,再其次我们用以表示左右二叉树的j-1和i-j这也是很难想出来的,可能需要一定的数学推理。这些条件都使这道题变得毫无头绪,不知道入手点在哪里,自然就做不出来。

总结:

今天我们完成了整数拆分&&不同的二叉搜索树两道题,相关的思想需要多复习回顾。接下来,我们继续进行算法练习。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1156074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VINS-Mono-VIO初始化 (五:视觉惯性对齐求解)

整体思想就是根据预积分的公式&#xff0c;把已知量和未知量各放到一边&#xff0c;因为前面的数据都是变换到 c 0 c_{0} c0​下的&#xff0c;不是真正意义上和重力对齐的世界坐标&#xff0c;然后位移和速度的预积分中会用到加速度计获取的重力加速度g&#xff0c;但是这个重…

Spring循环依赖处理

循环依赖是指两个或多个组件之间相互依赖&#xff0c;形成一个闭环&#xff0c;从而导致这些组件无法正确地被初始化或加载。这种情况可能会在软件开发中引起问题&#xff0c;因为循环依赖会导致初始化顺序混乱&#xff0c;组件之间的关系变得复杂&#xff0c;甚至可能引发死锁…

基于若依的ruoyi-nbcio流程管理系统增加仿钉钉流程设计(四)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 这里继续上面的章节&#xff0c;讲讲角色的选择与节点表单的选择。 1、角色的选择 加上下面选择角色的界…

低级语言汇编真的各个面不如汇编吗?

今日话题&#xff0c;低级语言汇编真的各个面不如C语言吗&#xff1f;C语言因其可移植性、开发效率和可读性而在各领域广泛使用&#xff0c;市场占有率极高。然而&#xff0c;汇编语言在特定场景下仍然具有独特优势&#xff0c;稳固地占据一席之地。如果你对这方面感兴趣&#…

使用轻量应用服务器搭建在线写作利器StackEdit

使用轻量应用服务器搭建在线写作利器StackEdit 前言 我经常会分享自己的一些搭建记录&#xff0c;所以我需要一个比较顺手的&#xff0c;Markdown编辑器。最开始我选择使用了CodiMD&#xff0c;但是我慢慢发现&#xff0c;我有一些快速功能CodiMD无法实现&#xff0c;我就转而…

Nginx热升级的完整流程

热升级的完整流程如下&#xff1a; 1.将旧的Nginx二进制文件换成新的Nginx二进制文件&#xff0c;注意需要把旧的Nginx二进制备份好。 2.向master进程发送USR2信号。 3.master进程修改pid文件&#xff0c;加.oldbin后缀。 4.master进程用新的nginx文件启动新的master进程。 5.向…

shell编程基础(第15篇:文件操作相关命令)

前言 计算机磁盘中存储的是文件&#xff08;目录也算文件的一种&#xff09;&#xff0c;常见的文件操作命令有cd、ls、mkdir、rm、等等涉及到文件的增删改查&#xff0c;今天一起学习常见的文件操作命令&#xff0c;come on baby&#xff01; cd change directory的首字母缩写…

php收发邮件的多种方法?

1、添加扩展&#xff1a; # 第一种&#xff1a; composer require php-imap/php-imap # 第二种&#xff1a; composer require phpmailer/phpmailer2、这里采用第二种方式&#xff1a; <?php declare(strict_types1);namespace App\Controller\v1\email;use App\Controll…

Java中String的split函数的详解及应用

文章目录 一、 split函数详解二、应用 一、 split函数详解 split(String regex)为java.lang.String类的方法&#xff0c;其功能通俗的说就是以传入的分隔符参数拆分该字符串 方法具体为&#xff1a; public String[] split(String regex) {return split(regex, 0); }方法内部…

pycharm怎么运行python代码

创建项目 在PyCharm中&#xff0c;你可以创建一个项目来组织和管理你的Python代码。项目是一个存放代码文件的文件夹&#xff0c;它可以包含多个模块和包。 启动PyCharm后&#xff0c;选择“Create New Project”来创建一个新项目。 在弹出的对话框中&#xff0c;选择项目的位…

作品展示-

------------校二手交易平台---------- ---------植物大战僵尸修改器------------- -------------商品进销存系统------------- --------汽车车牌号码识别系统----------- ------------示波器---------------- ---------激光数据传输仪------------ -----------32*64双色点阵屏…

听GPT 讲Rust源代码--library/std(9)

题图来自 Rust 101 — Everything you need to know about Rust[1] File: rust/library/std/src/sys/wasi/io.rs 在Rust源代码中&#xff0c;rust/library/std/src/sys/wasi/io.rs文件的作用是实现了与WASI&#xff08;WebAssembly System Interface&#xff09;IO相关的功能。…

Leetcode2086. 从房屋收集雨水需要的最少水桶数

Every day a Leetcode 题目来源&#xff1a;2086. 从房屋收集雨水需要的最少水桶数 解法1&#xff1a;贪心 我们可以对字符串 hamsters 从左到右进行一次遍历。 每当我们遍历到一个房屋时&#xff0c;我们可以有如下的选择&#xff1a; 如果房屋的两侧已经有水桶&#xff…

行业追踪,2023-10-31

自动复盘 2023-10-31 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

Linux0.11内核源码解析-exec.c

主要实现对二进制可执行文件和shell文件的加载和执行&#xff0c;其中主要的函数是do_execve(),它是系统中断调用int 0x80的功能号__NR_execve()调用&#xff0c;是exec()函数的主要实现以下几点功能&#xff1a; 1.执行对参数和环境参数空间页面的初始化操作&#xff0c;初始…

2023年09月 Python(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试&#xff08;1~6级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 yyh[2023,杭州亚运会,[拱宸桥,玉琮莲叶]] jxwyyh[2][0] print(jxw[1]*2)以上代码运行结果是&#xff1f;&#xff08; …

[已解决]ERROR tool.ExportTool: Error during export: Export job failed!

ERROR tool.ExportTool: Error during export: Export job failed! 问题 sqoop导出数据的时候遇到问题&#xff0c;ERROR tool.ExportTool: Error during export: Export job failed 思路 sqoop的shell命令是这样的 sqoop export –connect jdbc:mysql://cdh00:3306/airq…

JDK常用性能监控和故障处理工具

JDK8 在JDK安装目录下的bin文件夹&#xff0c;有一些辅助命令行工具&#xff0c;通常用来获取JVM的信息或者监控JVM&#xff0c;在排查性能问题方面是非常好用的工具。以Centos7.9系统下的openJDK1.8.0_222为例&#xff08;不同大版本的JDK命令的参数会有差异&#xff0c;不同操…

利用python进行数据分析 pdf

利用python进行数据分析 pdf 介绍 在现代社会中&#xff0c;随着大数据时代的到来&#xff0c;数据分析的需求越来越大。而Python作为一门简洁且易于学习的编程语言&#xff0c;具有强大的数据分析能力&#xff0c;成为了广大数据分析师的首选工具之一。本文将指导一位刚入行的…

相关性网络图 | 热图中添加显著性

一边学习&#xff0c;一边总结&#xff0c;一边分享&#xff01; 本期教程 写在前面 此图是一位同学看到后&#xff0c;想出的一期教程。 最近&#xff0c;自己的事情比较多&#xff0c;会无暇顾及社群和公众号教程。 1 安装和加载相关的R包 library(ggraph) library(tidy…