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

本文主要是介绍代码随想录算法训练营第四十一天| 343. 整数拆分,96.不同的二叉搜索树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目与题解

343. 整数拆分

题目链接:343. 整数拆分

代码随想录题解:343. 整数拆分

视频讲解:动态规划,本题关键在于理解递推公式!| LeetCode:343. 整数拆分_哔哩哔哩_bilibili

解题思路:

        一眼懵,直接看答案了

看完代码随想录之后的想法 

        前一天的题是由dp[i-2]和dp[i-1],递推出当前结果dp[i]。这题更复杂一些,是要根据dp[0]到dp[i-1],推算dp[i]的结果。

        对于数字i,可以分解为两个数字的和:j和i-j,因此求分解i的乘积,就是求j和分解i-j之后二者的乘积。那么如果dp[i]定义为数字i的最大乘积和,那么对于dp[i],遍历j from 1 to i - 1, 递推公式为求dp[i-j]*j和j * (i - j) 中的最大值。

        为避免重复计算,j最多取到i的一半。

class Solution {public int integerBreak(int n) {int[] dp = new int[n+1];if (n >= 2) dp[2] = 1;for (int i = 3; i <= n; i++) {for (int j = 1; j <= i/2; j++) {dp[i] = Math.max(dp[i], Math.max(j*(i-j), dp[i-j]*j));}}return dp[n];}
}

j怎么就不拆分呢?

j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。那么从1遍历j,比较(i - j) * j和dp[i - j] * j 取最大的。递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));

也可以这么理解,j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘。

如果定义dp[i - j] * dp[j] 也是默认将一个数强制拆成4份以及4份以上了。

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

 还需要注意,初始化的方式是跟着定义走的,如果求的是max(dp[i - j] * dp[j]),为了计算正确,初始化的结果会跟dp[i]定义不符,容易出错。

遇到的困难

        第一次碰到这种题,想不到

96.不同的二叉搜索树 

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

代码随想录题解:​​​​​​​96.不同的二叉搜索树 

视频讲解:动态规划找到子状态之间的关系很重要!| LeetCode:96.不同的二叉搜索树_哔哩哔哩_bilibili

解题思路:

        这题跟上面一题有一点类似,同样是要用多个dp[i-j]的值推出dp[i]。

        题目要求用1-n的数字构成不同的二叉搜索树,其实可以分解为,0-j-1的数字构成左子树,j为根节点,j到i构成右子树,那么

dp[i] = \sum_{1}^{i}dp[j-1]*dp[i-j]

        初始化dp[0]=dp[1]=0即可。

class Solution {public int numTrees(int n) {int[] dp = new int[n+1];dp[0] = 1;dp[1] = 1;for (int i = 2; i <= n; i++) {for (int j = 1; j <= i ; j++) {dp[i] += dp[j-1] * dp[i-j];}}return dp[n];}
}

看完代码随想录之后的想法 

        以dp[3]为例

dp[3],就是 元素1为头结点搜索树的数量 + 元素2为头结点搜索树的数量 + 元素3为头结点搜索树的数量

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

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

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

关键是看如何去分解,分解后如何正确确定遍历的上下限。

遇到的困难

        一开始写的时候没有想清楚遍历的边界,初始化的时候也有点糊涂,所以错了好几处。要记住按定义初始化dp,然后确定遍历上下界后,最好通过几个举例得到结果,保证边界正确。        

今日收获

        学会了如何用分解的方法使用dp,难度提升了很多。

这篇关于代码随想录算法训练营第四十一天| 343. 整数拆分,96.不同的二叉搜索树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/910764

相关文章

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

Java集合之Iterator迭代器实现代码解析

《Java集合之Iterator迭代器实现代码解析》迭代器Iterator是Java集合框架中的一个核心接口,位于java.util包下,它定义了一种标准的元素访问机制,为各种集合类型提供了一种统一的... 目录一、什么是Iterator二、Iterator的核心方法三、基本使用示例四、Iterator的工

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

Vue实现路由守卫的示例代码

《Vue实现路由守卫的示例代码》Vue路由守卫是控制页面导航的钩子函数,主要用于鉴权、数据预加载等场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、概念二、类型三、实战一、概念路由守卫(Navigation Guards)本质上就是 在路

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni

JAVA实现Token自动续期机制的示例代码

《JAVA实现Token自动续期机制的示例代码》本文主要介绍了JAVA实现Token自动续期机制的示例代码,通过动态调整会话生命周期平衡安全性与用户体验,解决固定有效期Token带来的风险与不便,感兴... 目录1. 固定有效期Token的内在局限性2. 自动续期机制:兼顾安全与体验的解决方案3. 总结PS

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

Python屏幕抓取和录制的详细代码示例

《Python屏幕抓取和录制的详细代码示例》随着现代计算机性能的提高和网络速度的加快,越来越多的用户需要对他们的屏幕进行录制,:本文主要介绍Python屏幕抓取和录制的相关资料,需要的朋友可以参考... 目录一、常用 python 屏幕抓取库二、pyautogui 截屏示例三、mss 高性能截图四、Pill

使用MapStruct实现Java对象映射的示例代码

《使用MapStruct实现Java对象映射的示例代码》本文主要介绍了使用MapStruct实现Java对象映射的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、什么是 MapStruct?二、实战演练:三步集成 MapStruct第一步:添加 Mave