给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
思路:我们设 f ( n ) f(n) f(n)是将n拆分后的所能得到的最大值,则 f ( n ) = m a x ( 1 ∗ f ( n − 1 ) , 2 ∗ f ( n − 2 ) , . . . ) f(n)=max(1*f(n-1),2*f(n-2),...) f(n)=max(1∗f(n−1),2∗f(n−2),...),我们也可以画出他的递归树
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/aa711d2eee5496475021737d535e98aa.jpeg)
则我们设 r e s res res为最大值,则 r e s = m a x ( r e s , i ∗ i n t e g e r B r e a k ( n − i ) ) res=max(res,i*integerBreak(n-i)) res=max(res,i∗integerBreak(n−i)),但有时候n是不需要继续划分的,比如,当 n = 2 n=2 n=2时, 2 ∗ f ( n ) > 1 ∗ 1 ∗ f ( n ) 2*f(n)>1*1*f(n) 2∗f(n)>1∗1∗f(n),所以我们还要比较 i ∗ ( n − i ) i*(n-i) i∗(n−i)。所以 r e s = m a x ( r e s , m a x ( i ∗ ( n − i ) , i ∗ i n t e g e r B r e a k ( n − i ) ) ) ; res = max(res, max(i * (n - i), i * integerBreak(n - i))); res=max(res,max(i∗(n−i),i∗integerBreak(n−i)));
1 递归
int integerBreak(int n) {
//解法1 递归
if(n==2)
return 1;
int res=-1;
for(int i=1;i<n;i++)
{
res = max(res, max(i * (n - i), i * integerBreak(n - i)));
}
return res;
}
大量重复计算,时间超时。
2 带备忘录的递归
对递归进行优化
int integerBreak(int n) {
//解法2 带备忘录的递归
if(n==2)
return 1;
vector<int> memo(n+1,0);
int res=-1;
if(memo[n]!=0)
return memo[n];
for(int i=1;i<n;i++)
{
res = max(res, max(i * (n - i), i * integerBreak(n - i)));
}
memo[n]=res;
return res;
}
3 动态规划
时间复杂度为 O ( 3 n 2 ) O(3n^2) O(3n2),空间复杂度为 O ( n ) O(n) O(n)
int integerBreak(int n) {
//解法3 动态规划 dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]))
if(n==2)
return 1;
vector<int> dp(n+1,0);
dp[2]=1;
for(int i=3;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 贪心(数学方法)
这是大佬总结的,应尽可能的把n分为3的和,然后再拆成更多的 2,这样就能保证拆出来的整数的乘积结果最大。但我们也应该注意,当拆分为
7
=
3
+
3
+
1
7=3+3+1
7=3+3+1是没有
7
=
3
+
2
+
2
7=3+2+2
7=3+2+2大的
(
3
∗
3
=
9
)
<
(
3
∗
2
∗
2
=
12
)
(3*3=9)<(3*2*2=12)
(3∗3=9)<(3∗2∗2=12)
所以应分为三种情况讨论:
1、$ n%3==0$ ,则直接将n分为
n
/
3
n/3
n/3个
3
3
3,求
3
n
/
3
3^{n/3}
3n/3。
2、$ n%3==1 $ ,则直接将n分为 ( n − 1 ) / 3 − 1 (n-1)/3-1 (n−1)/3−1个 3 3 3,和俩个2,求 3 n / 3 − 1 + 2 ∗ 2 3^{n/3-1}+2*2 3n/3−1+2∗2。
3、$ n%3==2$ ,则直接将n分为 ( n − 2 ) / 3 (n-2)/3 (n−2)/3个 3 3 3,求 3 ( n − 2 ) / 3 ∗ 2 3^{(n-2)/3}*2 3(n−2)/3∗2。
int integerBreak(int n) {
if (n == 2) return 1;
if (n == 3) return 2;//这里3必须进行特判,不然b=0,返回的是3^1=3,这个结果是没有进行划分
int b=n%3;
if(b==0)
{
int a=n/3;
return pow(3,a);
}
if(b==1)
{
int a=(n-1)/3;
return pow(3,a-1)*4;
}
int a=(n-2)/3;
return pow(3,a)*2;
}