整數拆分
給定一個正整數 n,將其拆分爲至少兩個正整數的和,並使這些整數的乘積最大化。 返回你可以獲得的最大乘積。
示例 1:
輸入: 2
輸出: 1
解釋: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
輸入: 10
輸出: 36
解釋: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
說明: 你可以假設 n 不小於 2 且不大於 58。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/integer-break
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
用算術集合均值不等式
package dp;
import java.util.Scanner;
public class 整數拆分 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
//算術幾何均值不等式,等號當且僅當n1=n2=``na
//推論以,若拆分的數量a確定,則各拆分數字相等時,乘積最大
//將數字n儘可能以因子3等分時,乘積最大
if(n<=3){
System.out.println(n-1);
return;
}
int a=n/3;//整數部分
int b=n%3;//餘數部分
if(b==0){
System.out.println((int)Math.pow(3,a));
return;
}
if(b==1){
//若餘數爲1,應該把3+1替換位2+2,因爲2*2>3*1
System.out.println((int)Math.pow(3,a-1)*4);
return;
}
//餘數爲2,則不再拆分,2>1*1
System.out.println((int)Math.pow(3, a)*2);
}
}
動態遞歸:
package dp;
import java.lang.reflect.Array;
import java.util.Scanner;
public class 整數拆分動態規劃 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int[] dp=new int[n+1];
//狀態數組dp[i]表示數字i拆分爲至少兩個正整數之和的最大乘積。,爲了方便計算,dp的長度是n+1,值初始化爲1
//顯然dp[2]等1,外層循環從3開始遍歷,一直到n停止,內層循環j從1開始遍歷,一直到i之前停止,代表數字i可以拆分位j+(i-j_
//但j*(i-j)不一定是最大的乘積,因爲i-j不一定大於dp[i-j]數字i-j拆分成整數之和的最大乘積,這裏要選擇最大值作爲dp[i]的結果
//空間複雜度是 O(N)O(N),時間複雜度是 O(N^2)O(N^2)
dp[2]=1;
for(int i=3;i<=n;i++){
for(int j=1;j<=i-1;j++){
dp[i]=Math.max(dp[i],Math.max(j*dp[i-j],j*(i-j)));
}
}
System.out.println(dp[n]);
}
}
暴力搜索
上述表達式是表明n - i需要繼續分解的情況,但如果n - i比F(n - i)要大,顯然就不用再繼續分解了。故我們還需要比較i * (n - i)與i * F(n - i)的大小關係。所以完整的表達式應該爲:
作者:97wgl
鏈接:https://leetcode-cn.com/problems/integer-break/solution/bao-li-sou-suo-ji-yi-hua-sou-suo-dong-tai-gui-hua-/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
package dp;
import java.util.Scanner;
public class 整數拆分暴力解法 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
System.out.println(integerBreak(n));
}
public static int integerBreak(int n){
if(n==2){
return 1;
}
int res=-1;
for(int i=1;i<=n;i++){
res=Math.max(res,Math.max(i*(n-i),i*integerBreak(n-i)));
}
return res;
}
}
記憶化數組
package dp;
import java.util.Scanner;
public class 整數拆分記憶化搜索 {
private static int[] memory;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
memory = new int[n+1];
System.out.println(integerBreakHelper(n));
}
public static int integerBreakHelper(int n){
if(n==2)
return 1;
//memory的初值位0,如果它不爲0,說明已經計算過了,直接返回即可
if(memory[n]!=0)
return memory[n];
int res=-1;
for(int i=1;i<=n-i;i++)
res=Math.max(res, Math.max(i*integerBreakHelper(n-i), i*(n-i)));
//把每次的結果保存到備忘錄數組中
memory[n]=res;
return res;
}
}