343. 整数拆分
难度 中等
给定一个正整数 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
题解
官方给出了动态规划和数学方法,就讲一下动态规划方法吧。
动态规划
当我们要求最大乘积,我们需要进行拆分,然后乘积。那怎么进行拆分才能是乘积最大呢,当没有办法的时候,就暴搜所有拆分,然后分别求乘积。
但是暴搜的时候,经常需要计算比较小的数,比如2拆分成1 * 1 = 1,3拆分成1 * 2 = 2等等。那我们可以利用动态数组记录下当前值最大乘积dp[2] = 1, dp[3] = 2,dp[4] = 4等,这样拆分的时候就不需要重新计算,也称记忆搜索法。
我们只需要两层循环,第一次遍历状态,第二层遍历拆分,然后结合记忆搜索法,那么动态转移方程为:dp[i] = max( j * (i - j), j * dp[i - j])
class Solution {
public int integerBreak(int n) {
int[] dp = new int[n + 1];//动态数组
for(int i = 2; i <= n; i++){//遍历状态
int max = 0;
for(int j = 1; j < i; j++){//遍历拆分
max = Math.max(max, Math.max(j * (i - j), j * dp[i - j]));//动态转移方程
}
dp[i] = max;
}
return dp[n];
}
}
动态规划优化
上面的动态规划如何优化呢,我们很容易找到一个数4,为什么是这个数,4可以拆分2 * 2 = 4,这是它的一个特点,如果小于4的数,1,2,3,这三个数无论如何拆分,最大乘积都不会大于本身。5,6,7,8等等可以拆分,然后求最大乘积都会大于本身。所以我们拆分最小的数是1,2,3,但是1不能拆分就去掉。
有了这个只是少了第二层循环的1而已,并没有优化什么,其实我们再把大于等于4的数进行拆分,4 = 2 + 2,5= 2 + 3,6 = 3 + 3,这些都可以进行拆分成多个2和3,那最后都是2和3的乘积,所以第二层循环可以去掉,然后动态转移方程为dp[i] = max(max(2 * (i - 2), 2 * dp[i - 2]), max(3 * (i - 3), 3 * dp[i - 3]));
class Solution {
public int integerBreak(int n) {
if(n < 4){//小于4,返回n-1
return n -1;
}
int[] dp = new int[n + 1];//动态数组
dp[2] = 1;
for(int i = 3; i <= n; i++){
dp[i] = Math.max(Math.max(2 * (i - 2), 2 * dp[i - 2]), Math.max(3 * (i - 3), 3 * dp[i - 3]));//动态转移方程
}
return dp[n];
}
}