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

力扣343-整数拆分(Java详细题解)

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

前情提要:

因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。

dp五部曲。

1.确定dp数组和i下标的含义。

2.确定递推公式。

3.dp初始化。

4.确定dp的遍历顺序。

5.如果没有ac打印dp数组 利于debug。

每一个dp题目如果都用这五步分析清楚,那么这道题就能解出来了。

题目思路:

本题要求把n拆分为k个正整数和并使这些乘积最大化。

那么我们应该将n拆成几个数呢?拆成俩个?三个?四个?

不好确认是吧。

我们先按照递归五部曲来解析题目。

1.确定dp数组和i下标的含义。

dp[i]就是指将i拆分后获得的最大乘积。

2.确定递推公式。

在确定递推公式之前,我们应该先模拟几遍,找找规律。

比如将10拆分为 2 和 8,8 其实也可以拆分为 2 和 6,6又可以拆分为 2 和 4等等。

其实后面拆分的其实都是8对吧。

那我们可以从中获得以下什么规律呢?

可以简单将i拆分为俩个部分或者多个部分。

拆分为俩个部分的情况,我们需要一个j对i进行遍历,即俩部分拆分为j * (i - j)。

举个例子就是上面的 10 依次可以拆分为 1 9、2 8、3 7等等。

拆分为多个部分的情况,就是j * dp[i - j],其实就是将i - j再进行拆分,得到他i - j的最大乘积。即拆分为多个部分的情况,可以将i - j拆分为俩个也可能是三个等等。所得到的就是将i拆分成了多个部分。

我们是要得到拆分后的最大值,那么每次拆分时,我们都应该将这俩种情况取一个最大值。Math.max(j * (i - j),j * dp[i - j])。

然后我们是要得到dp[i] 的最大值 所以我们的递推公式就是dp[i] = Math.maxa(dp[i],Math.max((j * (i - j),j * dp[i - j]))。

这里我们还需要将每次拆分的俩种情况的最大值跟前几次拆分的最大值进行比较,这样最后得到的就是拆分所有情况后所得到的最大乘积。

3.dp初始化。

这道题的dp初始化很巧妙。

dp[0]和dp[1]都没有意义,因为dp[i] 是让i拆分为k个正整数,1 和 0 都不能再拆,所以我们直接初始化dp[2]就好。

4.确定dp的遍历顺序。

我们先看看dp数组,dp[i] = Math.maxa(dp[i],Math.max((j * (i - j),j * dp[i - j]))。

dp[i]是需要dp[i - j]的状态,即需要他前面的状态,所以遍历顺序一定是从前向后遍历,现有dp[i - j]再有dp[i]。

5.如果没有ac打印dp数组 利于debug。

最后dp[i]模拟后情况就是这样,大家可以打印dp数组对着看看哪与你的不符。

在这里插入图片描述

具体还有一些细节我们就在代码中讲。

最终代码:

class Solution {
    public int integerBreak(int n) {
        int dp[] = new int [n + 1];
        dp[2] = 1;
        //该题主要就是递推公式
        //为什么这里i从3开始遍历
        //因为前面 1 和 0都没有意义 2已经初始化了 所以从3开始遍历
        for(int i = 3;i <= n;i ++){
            //里面就是拆分的逻辑
            for(int j = 1;j <= i / 2;j ++){
                //为什么这里 j 不从0开始呢? 如果j = 0的话 那0 乘以任何数都为 0 就没有意义 所以j 从 1开始
                //为什么这里j <= i/2 而不是 i 呢,其实这里是一个优化。
                //当j = i时其实跟j = 0时没有区别 所以j不能等于 i
                //为什么是 i / 2 呢,其实当一个数拆分为多个近似相等的数时,才能得到他的最大乘积,这是一个数学定理。
                //比如10 是拆分 3 3 4。
                //9 拆分为 3 3 3.并且你可以自己模拟,当10拆分为 6 和 4 的时候 一定比 5 5要小。
                //所以我们拆分i时,就拆分到i / 2即可,后面比i / 2大的肯定拆分的乘积都比前面小。
                dp[i] = Math.max(dp[i],Math.max(j * (i - j),j * dp[i - j]));
            }
        }
        return dp[n];
    }
}

这一篇博客就到这了,如果你有什么疑问和想法可以打在评论区,或者私信我。

我很乐意为你解答。那么我们下篇再见!


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

相关文章:

  • 动态规划问题-删除并获得点数(Java实现)
  • conda创建 、查看、 激活、删除 python 虚拟环境
  • 微服务day08
  • Elasticsearch基本概念及使用
  • C++ 编程基础(6)作用域 | 6.3、类作用域
  • 微信小程序中使用离线版阿里云矢量图标
  • QNN:基于QNN+example重构之后的yolov8det部署
  • 经验笔记:NoSQL数据库及其缓存方法实践
  • 什么是单片机?为什么要学习单片机?
  • 【文献及模型、制图分享】县域城乡融合发展对乡村旅游地实现共同富裕的影响机制——以长三角地区60个典型县为例
  • Qt/QML学习-CircularGauge
  • Python函数的编写
  • 上海市计算机学会竞赛平台2024年8月月赛丙组调和级数
  • CMU 10423 Generative AI:HW0
  • 【计算机网络】socket编程 几个网络命令
  • 【机器学习】Boosting与Bagging算法
  • 哈希扩展(位图与布隆过滤器)
  • React基础教程(09):react的属性介绍(props)
  • 万界星空科技MES:企业实现数字化转型的护航者
  • SpringCloud之CircuitBreaker
  • 江协科技stm32————10-5 硬件I2C读写MPU6050
  • 宝扬笔记本电脑重做win10系统教程
  • 2024国赛数学建模C题完整论文:农作物的种植策略
  • 智 能 合 约
  • 【css】获取最后一个li进行样式特殊处理
  • 企微获客链接 中文乱码问题处理