343. 整数拆分
1.题目描述
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
示例 2:
说明: 你可以假设 n 不小于 2 且不大于 58。
2.方法1(动态规划)
dp[i]表示将正整数 i 拆分成至少两个正整数的和之后,这些正整数的最大乘积。特别地,0 不是正整数,1 是最小的正整数,0 和 1 都不能拆分,因此 dp[0]=dp[1]=0。
当 i≥2 时,假设对正整数 i 拆分出的第一个正整数是 j(1≤j<i),则有以下两种方案:
将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j×(i−j);
将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j×dp[i−j]。
因此,当 j 固定时,有dp[i]=max(j×(i−j),j×dp[i−j])。由于 j 的取值范围是 1 到 i−1,需要遍历所有的 j 得到 dp[i] 的最大值,因此可以得到状态转移方程如下:
dp[i] = max{max(j×(i−j),j×dp[i−j])}
最终得到 dp[n] 的值即为将正整数 n 拆分成至少两个正整数的和之后,这些正整数的最大乘积。
3.代码
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n+1);
for(int i = 2;i <= n;++i){
for(int j = 1;j < i;++j){
dp[i] = max(dp[i],max(j*(i-j),j*dp[i-j]));
}
}
return dp[n];
}
};
4.复杂度分析
时间复杂度:O(n^2)
空间复杂度:O(n)
5.方法2(数学法)
当两个整数尽量平分n的时候,两个整数的乘积才能达到最大,(比如,当n = 10时,分成两份,必定是5, 5。当n = 11时,分成两份,必定是5、6)
推广:
将n 分成cnt份(cnt <= n),必定是(n % cnt) 个 (n / cnt + 1)和 (cnt - n % cnt )个 (n / cnt)乘积最大。(其中n / cnt是表示均分所得,n % cnt是表示均分成cnt份后多出的1个数,再分给其中 n % cnt 个 n / cnt)(比如,n = 10,求分成cnt = 3份的最大乘积。均分所得 num = n / cnt = 3, 多出的1的个数 为 n % cnt = 1, 再将多出的1分配到其中均分所得的元素中,n / cnt + 1)
6.代码
class Solution {
public:
int integerBreak(int n) {
int res = 0;
for(int i = 2;i <= n;++i){
int numCount = n % i;//多出1的个数
res = max(res,(int)(pow(n/i,i-numCount)*pow(n/i+1,numCount)));
}
return res;
}
};
7.复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)