解题思路:有动态规划和贪心两种方法。
- 贪心
通过打表我们发现这样的规律:一个数拆分达到最大一定是其拆乘3的个数达到最大,但如果结尾剩下1的话要少拆1个3从而拼成1个4。 - 动态规划
dp[i]:表示将长度为i的线段裁剪为m段的乘积最大值 (2 <= m <= n)
转移方程:dp[i] = dp[j] * dp[i-j] (1 <= j <= i/2)
class Solution {
public:
int maxProductAfterCutting(int length) {
return Solve_2(length);
}
int Solve_1 (int len) {
/** * dp[i] : 表示将长度为i的线段裁剪为m段的乘积最大值 (2 <= m <= n) * 转移方程 : dp[i] = dp[j]*dp[i-j] (1 <= j <= i/2) ::至少两段(i/2,i-i/2) 最多n段(1,...,1) */
if (len < 4) {
return len-1;
}
vector<int> dp(len+1, 0);
dp[1] = 1;
dp[2] = 2;
dp[3] = 3;
for (int i = 4; i <= len; i++) {
for (int j = 1; j <= i/2; j++) {
dp[i] = max(dp[i], dp[j]*dp[i-j]);
}
}
int res = 0;
for (int i = 4; i <= len; i++) {
res = max(res, dp[i]);
}
return res;
}
int Solve_2 (int len) {
/** * 贪心 : * len = 1, res = 1 * len = 2, res = 1 * len = 3, res = 2 * len = 4, res = 4 (2*2) * len = 5, res = 6 (2*3 || 3*2) * len > 5, res = 3^(len/3)*(剩下的数(>1)) * 我们发现若要让乘积越大,必定要将数拆出的3的个数尽量多,不过当剩下为1的时候前一个不能拆乘3要转乘2*2 */
if (len < 4) {
return len-1;
}
if(len == 4) {
return 4;
}
if (len % 3 == 1) {
return pow(3, len/3-1)*4;
}
return pow(3, len/3)*(len-len/3*3 == 0?1:2);
}
};