整数拆分
给定一个正整数 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;
}
}