携手创作,共同成长!这是我参与「掘金日新计划 · 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];
}
}
结语
业精于勤,荒于嬉;行成于思,毁于随。