题目描述
给定一个正整数 n
,将其拆分为 k
个 正整数 的和( k >= 2
),并使这些整数的乘积最大化。
返回 你可以获得的最大乘积 。
问题分析
将正整数 n 拆分为 k 个正整数的和,情况比较多,我们可以先考虑简化版本,即将正整数拆分成 2 个正整数的和,求乘积的最大值。
若只拆分成两个数,对于正整数 n,我们只需要遍历整数 i,使得i * (n - i)
的值取最大即可。
接下来,我们进一步考虑拆分成 k 个正整数的情况。可以采用递归求解的思想思考该问题,定义solve(i)
表示将整数 i 拆分成 2 个及 2 个以上正整数的和,对应乘积的最大值。
将整数 n 拆分成 2 个正整数的情况,上述的简化版本已经讨论过了。而 2 个以上的正整数,我们可以借助solve(i)
来实现,即solve(n) = max( i*(n-i), i*solve(n-i) )
i * (n - i)
:表示拆分成 2 个正整数i * solve(n - i)
:表示拆分成 2 个以上正整数
这里我们分析采用的是自上而下的分析策略,对应实现的时候,可以采取动态规划自下而上的求解策略。
算法描述
状态定义:dp[i]
表示将正整数 i 拆分成至少两个正整数之和后,乘积的最大值。
状态计算:
dp[i] = max( j * (i - j), j * dp[i - j] )
边界条件:
dp[0] = 0
:0 不能拆分成两个正整数之和dp[1] = 0
:1 不能拆分成两个正整数之和
复杂度分析
时间复杂度为 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( n ) O(n) O(n)
程序代码
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n + 1, 0);
for(int i = 2; i <= n; i++) {
for(int j = i - 1; j >= 1; j--) {
// 拆分成两个
dp[i] = max(dp[i], j * (i - j));
// 拆分成两个以上
dp[i] = max(dp[i], j * dp[i - j]);
}
}
return dp[n];
}
};