每天一道算法题系列:
来源:力扣(LeetCode)
本题链接:https://leetcode-cn.com/problems/integer-break/
来源是力扣,大家喜欢可以去力扣中文网做相应的其他的题,某浏览器直接搜力扣即可。
本题难度是中等
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
/*
怎么说这道题呢,我感觉我的知识储备不是很好的解释这道题。我把大佬的解题过程拿过来。
对于的正整数n,n≥2时,可以拆分成至少两个正整数的和。令k是拆分出的第一个正整数,则剩下的部分是n-k,n−k可以不继续拆分,或者继续拆分成至少两个正整数的和。由于每个正整数对应的最大乘积取决于比它小的正整数对应的最大乘积,因此可以使用动态规划求解。
创建数组ints,其中ints[i]表示将正整数i拆分成至少两个正整数的和之后,这些正整数的最大乘积。特别地,0不是正整数,1是最小的正整数,0和1都不能拆分,因此 ints[0] = 0,ints[1] = 0。
当i≥2时,假设对正整数i拆分出的第一个正整数是j(1≤j<i),则有以下两种方案:
将i拆分成j和i−j的和,且i−j不再拆分成多个正整数,此时的乘积是j×(i−j);
将i拆分成j和i−j的和,且i−j继续拆分成多个正整数,此时的乘积是j×ints[i−j]。
因此,当j固定时,有dp[i]=max(j×(i−j),j×dp[i−j])。由于j的取值范围是1到i−1,需要遍历所有的j得到dp[i]的最大值.
ints[i] = Math.max(ints[i],(i-j)*j > j*ints[i-j]?(i-j)*j:j*ints[i-j]);
这个方法比递归的方式会好一些,相当于就是把递归需要重新计算的数组量给保存了,不需要再次计算
*/
public class IntegerBreak {
public static int integerBreak(int n) {
int[] ints = new int[n +1 ];
int max = 0;
for (int i = 2; i <= n; i++) {
for (int j = 1; j <i; j++) {
/*
发现一个事,一般用Math.max,不用三元运算符,这样内存消耗少一点
Math.max((i-j)*j, j*ints[i-j]) 好于j*ints[i-j]?(i-j)*j:j*ints[i-j]
*/
ints[i] = Math.max(ints[i],(i-j)*j > j*ints[i-j]?(i-j)*j:j*ints[i-j]);
}
}
return ints[n];
}
public static void main(String[] args) {
System.out.println(integerBreak(10));
}
}
上一篇文章:每天一道算法题系列二十七之旋转数组的最小数字
如果本篇内容有问题,请第一时间联系我,我会第一时间修改。
谢谢大家。