给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
因为n可以拆分成两个数,也可以拆分多个数。 拆分成两个数的时候乘积就是i * (n - i),也可以选择继续拆分:integerBreak(n - i)就是将n - i继续拆分的结果,但是我们并不知道种哪拆分的结果更大,所以我们要取二者的较大值作为当前拆分的最大值。
class Solution {
int n;
int ans;
public int integerBreak(int n) {
this.n=n;
dfs(1,0,1);
return ans;
}
void dfs(int start,int sum,int mult){
if(sum==n){
if(mult>ans) ans=mult;
return ;
}
for(int i=start;i<=n-1;i++){
if(sum+i>n) break;
dfs(i,sum+i,mult*i);
}
}
}
递归自顶向下容易超时,所以再加上一个备忘录。
这个备忘录可以是HashMap也可以是数组。
class Solution {
HashMap<Integer,Integer> hash=new HashMap<>();
public int integerBreak(int n) {
if(n==2) return 1;
//如果有key值n,就直接返回value
if(hash.containsKey(n)) return hash.get(n);
//下面是没有key,就要计算,然后加入到hash中
int res=-1;
for(int i=1;i<=n-2;i++){
res=Math.max(res,Math.max((n-i)*i,integerBreak(n-i)*i));
}
hash.put(n,res);
return res;
}
}
因为memory需要分配内存,不可能再递归函数里面分配,所有要再加一个函数
class Solution {
// 记忆化搜索-自顶向下
int[] memory;
//因为memory需要分配内存,不可能再递归函数里面分配,所有要再加一个函数
public int integerBreak(int n) {
memory = new int[n + 1];
return integerBreakHelper(n);
}
public 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 - 2; i++) {
res = Math.max(res, Math.max(i * integerBreakHelper(n - i), i * (n - i)));
}
// 将每次计算的结果保存到备忘录数组中
memory[n] = res;
return res;
}
}
动态规划
class Solution {
public int integerBreak(int n) {
int[] dp=new int[n+1];
dp[2]=1;
for(int i=3;i<=n;i++){
for(int j=1;j<=i-2;j++){
dp[i]=Math.max(dp[i],Math.max(j*(i-j) , j*dp[i-j]));
}
}
return dp[n];
}
}