06.整数拆分
- 题目描述
给定一个正整数 n
,将其拆分为 k
个 正整数 的和( k >= 2
),并使这些整数的乘积最大化。返回 你可以获得的最大乘积 。
示例 1:
输入: n = 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: n = 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
- 题目分析
整体思路
要想将一个整数拆分成若干个整数之后求得若干个整数的乘积最大值
根据数学规律我们可以知道将一个数拆分成若干个数,要想数的乘积
越大,那么它们应该尽可能相同即可。
存在误区
那么是不是直接将它们均分就可以呢?那么以8为例子吧:
分成两份尽可能相等:8/2 = 4 [4,4]
分成三份尽可能相等:8/3 = 2 [2,2,4]此时乘积为16
但如果分成[2,3,3]此时乘积为18
所以我们不可以直接以均分为标准,这样可能会出现上述的问题
如何避免误区?
那么为什么会出现上面的问题呢?
那是因为在均分成整数的过程中,可能会出现不均匀的情况,所以我们在分的时候
可采取下面的策略:
8分成三份尽可能相等[2,3,3]
8
/|
2 6
/|
3 3
8分成五份尽可能相等[1,1,2,2,2]
8
/|
1 7
/|
1 6
/|
2 4
/|
2 2
即将每次分成两个数相加,左子树表示均分k,k-1...2后的一份,右子树为剩余要分的部分这样每次将一个数均分成两份,使得二者相差小于等于1,就不会出现不良均分的情况了
可以根据上述分析直接写出代码
- Java代码实现
public static int integerBreak(int n) {
int res = 1, max = 0, a, range = n;
for (int i = 2; i <= range; i++) {//i表示要分割的范围2~n
for (int j = i; j >= 1; j--) {//j表示依次均分
a = n / j;
res = res * a;
n = n - a;
}
if (res >= max) {
max = res;
n = range;
res = 1;
} else {//当发现小于最大的值退出循环,因为是先增后减函数
break;
}
}
return max;
}
同时此题也可以用动态规划去做,大家可以参考代码随想录的解法
public int integerBreak(int n) {
//dp[i] 为正整数 i 拆分后的结果的最大乘积
int[] dp = new int[n+1];
dp[2] = 1;
for(int i = 3; i <= n; i++) {
for(int j = 1; j <= i-j; j++) {
dp[i] = Math.max(dp[i], Math.max(j*(i-j), j*dp[i-j]));
}
}
return dp[n];
}