方法一:动态规划
对于的正整数 \(n\),当 \(n \ge 2\) 时,可以拆分成至少两个正整数的和。令 \(k\) 是拆分出的第一个正整数,则剩下的部分是 \(n-k\),\(n-k\) 可以不继续拆分,或者继续拆分成至少两个正整数的和。由于每个正整数对应的最大乘积取决于比它小的正整数对应的最大乘积,因此可以使用动态规划求解。
创建数组 \(\textit{dp}\),其中 \(\textit{dp}[i]\) 表示将正整数 \(i\) 拆分成至少两个正整数的和之后,这些正整数的最大乘积。特别地,\(0\) 不是正整数,\(1\) 是最小的正整数,\(0\) 和 \(1\) 都不能拆分,因此 \(\textit{dp}[0]=\textit{dp}[1]=0\)。
当 \(i \ge 2\) 时,假设对正整数 \(i\) 拆分出的第一个正整数是 \(j\)(\(1 \le j < i\)),则有以下两种方案:
将 \(i\) 拆分成 \(j\) 和 \(i-j\) 的和,且 \(i-j\) 不再拆分成多个正整数,此时的乘积是 \(j \times (i-j)\);
将 \(i\) 拆分成 \(j\) 和 \(i-j\) 的和,且 \(i-j\) 继续拆分成多个正整数,此时的乘积是 \(j \times \textit{dp}[i-j]\)。
因此,当 \(j\) 固定时,有 \(\textit{dp}[i]=\max(j \times (i-j), j \times \textit{dp}[i-j])\)。由于 \(j\) 的取值范围是 \(1\) 到 \(i-1\),需要遍历所有的 \(j\) 得到 \(\textit{dp}[i]\) 的最大值,因此可以得到状态转移方程如下:
\[\textit{dp}[i]=\mathop{\max}\limits_{1 \le j < i}\{\max(j \times (i-j), j \times \textit{dp}[i-j])\} \]最终得到 \(\textit{dp}[n]\) 的值即为将正整数 \(n\) 拆分成至少两个正整数的和之后,这些正整数的最大乘积。
class Solution {
public:
int integerBreak(int n) {
vector<int> f(n + 1);
for (int i = 2; i <= n; i++)
for (int j = 1; j < i; j++)
f[i] = max(f[i], max(j * (i - j), j * f[i - j]));
return f[n];
}
};