LeetCode343.整数拆分

文档参考:代码随想录

视频参考:LeetCode:343. 整数拆分_哔哩哔哩_bilibili

题目:LeetCode343.整数拆分

题目

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

示例 1:

  • 输入: 2
  • 输出: 1
  • 解释: 2 = 1 + 1, 1 × 1 = 1。

示例 2:

  • 输入: 10
  • 输出: 36
  • 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
  • 说明: 你可以假设 n 不小于 2 且不大于 58。

解决框架

动规五部曲:

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp的初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

详细解析

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

dp[]是用来存放整数拆分后最大乘积的数组。
i表示当前数字,dp[i]表示把i拆分后所得到的最大乘积

2.确定递推公式

首先如果将数字i拆分成两个数字,结果应该是j * (i - j)

其次如果要将数字i拆分成两个及两个以上的数字,结果应是j * dp[i - j]

问题:既然要将i - j继续拆分,为什么j不需要拆分呢?
答:
假设j为1,i为5,i - j为4,那么要j * dp[i - j]为
1 * 1 * 3、1 * 1 * 1 * 2、1 * 1 * 1 * 1 * 1
1 * 2 * 2
当j为2时,如果对j进行拆分会变为1 * 1,而以1 * 1为前缀的乘积已经进行过运算

因此,我们得出结论,j遍历时为1个固定值,确定第一个乘数,得出所有可能的乘积进行比较

3.dp的初始化

因为dp是存放整数拆分后最大乘积的数组,明显可知,dp[0]和dp[1]没有存在意义,数组从下标2开始

dp[2] = 1,因为1 * 1 = 1

4.确定遍历顺序

 由于递归公式中dp[i] = j * dp[i - j],可知i拆分后的最大乘积由i - j拆分后的最大乘积决定,故遍历顺序从前往后

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), j * dp[i - j]));
            }
        }

问:为什么要进行两层循环?
答:i是遍历要拆分的数字,而j是从1到i - 2寻找要拆分成什么数字。

问:为什么j <= i - 2?
答:因为j = i - 1时,dp[i - j]变成了dp[1],而我们知道由于1不可拆分,dp[1]没有意义。

问:为什么dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]))?
答:Math.max(j * (i - j), j * dp[i - j]))是为了确定将数字i拆分成两个还是两个以上,而将得出的结果和dp[i]比较是因为j在遍历要拆分成的数字,这行语句要经历多次执行确定最大乘积

问:能否优化?
答:可以。

举例:6拆分后最大乘积是3 * 3,10拆分后最大乘积是3 * 3 * 4
我们可以发现拆分出来能得到最大乘积的数字不会超过原数字的一半,所以

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), j * dp[i - j]));
            }
        }
5.举例推导dp数组

最终代码

// 时间复杂度O(n ^ 2)
// 空间复杂度O(n)
class Solution {
    public int integerBreak(int n) {
        int[] dp = new int[n + 1];
        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), j * dp[i - j]));
            }
        }
        return dp[n];
    }
}

总结

这道题目本身需要注意递推公式,要使递推公式和dp数组的含义相融洽。
对于笔者而言,题目本身需要思考理解,并最终通过整体的代码去想通

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值