【LeetCode】343.整数拆分

57 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情

题目

给定一个正整数 n ,将其拆分为 k正整数 的和( k >= 2 ),并使这些整数的乘积最大化。

返回 你可以获得的最大乘积

示例 1

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

示例 2

输入: n = 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36

提示

  • 2 <= n <= 58

题解

思路

本题是求最大乘积,一般求最值问题,我们都可以使用动态规划的思想来解决,我们使用的动态规划解题六步骤如下:

确定 dp 数组以及下标的含义(dp数组可能是一维数组、二维数组等) 确定递推公式 dp 数组如何初始化 确定 dp 数组的遍历顺序,可能是正向遍历、反向遍历、斜向遍历等 举例推导dp数组,通过把dp数组打印出来,并和自己人脑计算的结果对比,用于调试使用 思考是否可以状态压缩,进一步提升空间效率 套用到整数拆分这个场景,如下所示:

确定 dp 数组以及下标的含义:根据题目描述,定义 dp[i] 表示将正整数 i 拆分成至少两个正整数的和之后,这些正整数的最大乘积。 确定递推公式:假设我们从正整数 i (i>2) 中拆出一个正整数 j (1<= j < i),相当于把 i 拆分成 j 和 i-j 两部分,那么接下来会有两种选择(状态): i-j 部分不再继续拆分,那么此时整数 i 拆分后的乘积是 j * (i-j) i-j 部分不再继续拆分,那么此时整数 i 拆分后的乘积是 j * dp(i-j) 因此,可以得出递推公式是 dp[i] = max{max(j*(i-j), jdp(i-j))},其中 1<= j < i,也就是遍历 j,每个循环中计算 max(j(i-j), jdp(i-j)),最终遍历完之后,取 max(j(i-j), j*dp(i-j)) 的最大值作为 dp[i] 的取值。 dp 数组初始化:题目要求 n>=2,因此,对于0和1我们赋值为 0 即可 确定 dp 数组的遍历顺序:从递推公式可以看到,我们是从小到大遍历的 举例推导dp数组,调试时使用 思考是否可以状态压缩:如果现在想不清楚,可以等我们写完上面代码后可以再考虑

代码

class Solution {
    public int integerBreak(int n) {
        // dp[i] 表示正整数i的拆分为两个或者多个正整数后的最大乘积
        int[] dp = new int[n+1];

        // dp数据初始化,题目要求n>=2,因此,对于0和1我们赋值为0即可
        dp[0] = 0;
        dp[1] = 0;

        // 循环迭代,i 从 2 开始
        for (int i=2; i<=n; ++i) {
            for (int j=1; j<i; ++j) {
                // 递推公式:dp[i] = max{max(j*(i-j), j*dp(i-j))}
                dp[i] = Math.max(dp[i], Math.max(j*(i-j), j*dp[i-j]));
            }
        }

        return dp[n];
    }
}

结语

业精于勤,荒于嬉;行成于思,毁于随。