/*
* P96面試題14:剪繩子
* 給定一個正整數 n,將其拆分爲至少兩個正整數的和,並使這些整數的乘積最大化。 返回你可以獲得的最大乘積
*/
public class T14
{
/*
* 解法一:動態規劃
* 令dp[n]爲n對應的最大乘積
* 維護這個最優解數組
* 註釋中的寫法是另一種理解方式
* 當拆分出的一部分的長度爲4時 這一段是否需要再進行拆分?
* 4=2*2 而小於4時 例如3 若拆分3 則得到1*2=2 結果將小於不拆分的結果
* 而當大於4時 例如5 拆分爲2*3=6 >5 所以4爲分界點
* 大於4的部分需要再進行拆分 小於4的部分則不需要拆分
* 此方法的時間複雜度爲O(n^2)
*/
public static int integerBreak(int n)
{
int dp[]=new int[n+1];
dp[1]=1;
for(int i=2;i<=n;i++)
{
for(int j=1;j<i;j++)
{
dp[i]=Math.max(dp[i], (i-j)*Math.max(dp[j], j));
}
}
return dp[n];
// int dp[]=new int[n+1];
// dp[1]=1;
// for(int i=2;i<=n;i++)
// {
// for(int j=1;j<i;j++)
// {
// if(j<=4)
// {
// dp[i]=Math.max(dp[i], (i-j)*j);
// }
// else
// {
// dp[i]=Math.max(dp[i],(i-j)*dp[j]);
// }
// }
// }
// return dp[n];
}
/*
* 解法二:貪心
* 首先由均值不等式中的算數平均數>=幾何平均數可知
* 將輸入的n拆分成多個相等的數時積最大
* 先假設最優拆法所拆出的每一個數都爲x
* 那麼一共會拆出n/x個數
* 設他們的積爲f(x) 則f(x)=x^(n/x)
* 爲了求f(x)的最大值 可以對其求導
* 過程省略
* 最終有 x=e時f(x)有極大值
* e=2.7 故優先拆成3 拆不成3則拆2
* 實際上當剩餘長度小於等於4時
* 剩餘部分不拆分即可(方法一中說明)
* 此方法的時間複雜度爲O(lgn)
*/
public static int integerBreak2(int n)
{
if (n < 2)
return 0;
if (n == 2)
return 1;
if (n == 3)
return 2;
int timesOf3=0;
while(n>3)
{
if(n<=4)
break;
timesOf3++;
n-=3;
}
return (int)(Math.pow(3, timesOf3))*(n);
}
/*
* 記錄一下另一種看到的思路
*
* class Solution {
public:
int integerBreak(int n) {
if(n==2){return 1;}
if(n==3){return 2;}
n-=2;
return pow(3,n/3)*(n%3+2);
}
};
*/
}