一、原题
Given a positive integer n, break it into the sum of at least two positive integers and maximize the product of those integers. Return the maximum product you can get.
For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return 36 (10 = 3 + 3 + 4).
Note: You may assume that n is not less than 2 and not larger than 58.
二、题意
给定一个大于1的正整数,求如何将这个数拆成几个正整数的和(至少要拆成两个),使得这几个正整数的乘积最大。
三、思路
动态规划思想:定义状态、求出状态转移方程
定义状态:从简单情况开始考虑:
- 整数2:2 = 1 + 1,则最大乘积为1;
- 整数3:3 = 2 + 1,则最大乘积为2;
- 整数4:4 = 3 + 1 = 2 + 2,则最大乘积为4。先考虑3 + 1,和为3的最大乘积为2(由上面推出的结果),比3还小,所以肯定选择3,所以选择3 + 1的最大乘积为3 × 1 = 3;考虑2 + 2,和为2的最大成绩为1,比2还小,所以选择2 + 2的最大乘积为2 × 2 = 4,比较这两种情况结果为4;
- 整数5:5 = 4 + 1 = 3 + 2,则最大乘积为6。同4一样推断。
- 整数6:6 = 5 + 1 = 4 + 2 = 3 + 3,最大乘积为9。考虑这三种情况,选择5 + 1的最大乘积为6,选择4 + 2的最大乘积为8,选择3 + 3的最大乘积为9,比较这三种情况,结果为9;
......
综上,对于一个正整数n,则n的组合情况有 n = (n - 1) + 1 = (n - 2) + 2 = ... ,对于其中一种情况(n - i)与i,可以如果(n - i)大于和为(n - i)的最大乘积(例如3,和为3的最大乘积为2,而3本身大于2,则选择3,不选择其最大乘积),则选择(n - i)本身,不选择和为(n - i)的最大乘积;否则选择和为(n - i)的最大乘积,所以**定义dp[i]表示和为i的最大乘积,则dp[i] = max{ max{i - x, dp[i - x]} * max{x, dp[x]},其中i > x >= i/2 } **
四、代码
class Solution {
public:
int getMax(int a, int b){
return a > b ? a : b;
}
int integerBreak(int n) {
int *dp = new int[n + 1];
dp[0] = 0;
dp[1] = 1;
int max;
for (int i = 2; i <= n; ++i) {
max = -1;
for (int j = i - 1; j >= i / 2; --j) {
max = getMax(max, (j > dp[j] ? j : dp[j]) * (i - j > dp[i - j] ? (i - j) : dp[i - j]));
}
dp[i] = max;
}
int res = dp[n];
delete[] dp;
return res;
}
};