1 题目
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
说明: 你可以假设 n 不小于 2 且不大于 58。
2 Java
2.1 方法一(最优子问题,无一般性)
将n分隔为2~n-1份,最大值将从中产生,且对于分隔为i份,最大值是将i份平均分隔
class Solution {
public int integerBreak(int n) {
int ans = 1;
// 将n分隔为2~n-1份,最大值将从中产生,且对于分隔为i份,最大值是将i份平均分隔
for(int i = 2; i < n; i++){
// 尽力将n平均分割成i份
int[] arr = new int[i];
int big = n - n / i * i;
for(int k = 0; k < i; k++){
if(big-- > 0) arr[k] = n / i + 1;
else arr[k] = n / i;
}
// 计算分隔成i份的最大乘积
int temp = 1;
for(int a: arr) temp *= a;
ans = Math.max(ans, temp);
}
return ans;
}
}
2.2 方法二(特解)
尽可能的拆成3,这样比较大,若余下4,拆成2+2
class Solution {
public int cuttingRope(int n) {
// 特殊情况
if(n <= 3) return n - 1;
// a是n中可拆出最多a个3,;b是n除3的余数
int a = n / 3, b = n % 3;
// 若正好整除
if(b == 0) return (int)Math.pow(3, a);
// 若余1;把一个3拿出来和余下的1拆为两个2
if(b == 1) return (int)Math.pow(3, a - 1) * 4;
// 若余2;
return (int)Math.pow(3, a) * 2;
}
}
2.3 方法三(动态规划迭代)
dp[n]代表n可被分隔后的最大乘积,状态转移方程是
dp[n] = Math.max(dp[n], dp[j] * dp[n - j]);
其中j∈[2, n-1)
class Solution {
public int cuttingRope(int n) {
if(n < 4) return n - 1;
// 创建备忘录
int[] dp = new int[n + 1];
// 初始化
dp[1] = 1; dp[2] = 2; dp[3] = 3;
// 向前步进;dp[n]代表n可被分隔后的最大乘积
for(int i = 4; i <= n; i++){
for(int j = 2; j < i; j++) dp[i] = Math.max(dp[i], dp[j] * dp[i - j]);
}
return dp[n];
}
}
优化
最小拆分成2就行,没必要1,j也无需拆到n-2,对称的,拆到2 ~ n-2的中间就行
class Solution {
public int cuttingRope(int n) {
if(n <= 3) return n - 1;
int[] dp = new int[n + 1];
dp[0] = 0; dp[1] = 1; dp[2] = 2; dp[3] = 3;
// 0123都已赋值
for(int i = 4; i <= n; i++){
// 最小拆分成2就行,没必要1,j也无需拆到n-2,对称的,拆到2~n-2的中间就行
for(int j = 2; j <= i / 2; j++) dp[i] = Math.max(dp[i], dp[j] * dp[i - j]);
}
return dp[n];
}
}