1、数学思维
参考:http://www.cnblogs.com/shihaochangeworld/p/5547436.html
public static int integerBreak(int n) {
if(n <= 3) return n - 1;
if (n%2==0) {
int numOf3 = n / 6 * 2;
int numOf2 = n % 6 / 2;
return (int) (Math.pow(3, numOf3) * Math.pow(2, numOf2));
} else {
int numOf3 = (n-3)/6*2+1;
int numOf2 = (n-3)%6/2;
return (int) (Math.pow(3, numOf3) * Math.pow(2, numOf2));
}
}
当 n >= 4 时,需要分奇数和偶数的情况:
(1)当 n 为偶数时,就会有 n / 6 * 2
个 3,这里需要注意的是,计算 3 的个数时,不是直接用的 n / 3
,而是通过 n / 6 * 2
来间接计算的。因为当 n 为偶数时,n % 3
的结果有 0、1、2
,当余数为 0、2
时,n / 3
个 3 是最优的(例如 8、12,且 3 的个数为偶数个 ),但是余数为 1
的时候,n / 3
肯定为奇数(因为 偶数 - 1 = 奇数
),此时应该从 n / 3
个 3 中分出一个 3 来和 1 组成 4,然后拆分成 2 + 2
,才能使结果达到最优。所以直接使用 n / 6 * 2
,这样求出来的 3 的个数为偶数个,且 n % 6
也为 0 或者偶数 2、4
(偶数 - 偶数 = 偶数
)。
(2)当 n 为奇数时,根据前面的情况,如果直接用 n / 6
(余数为 1、3、5
,其中 5 = 3 + 2
)计算 3 的个数,当余数为 3、5
时就会少计算一个 3,且当 n 为奇数时,n 拆分得到的 3 的个数一定为奇数个,因此可以转换一下,用 (n-3)/6*2+1
来计算 3 的个数,其中 (n - 3)
就转换为偶数了。
2、动归
参考:https://blog.csdn.net/u013575812/article/details/51194637
public static int integerBreak2(int n) {
if(n <= 3) return n - 1;
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
dp[3] = 3;
for(int i = 4; i <= n; ++i)
{
dp[i] = Math.max(2 * dp[i - 2], 3 * dp[i - 3]);
}
return dp[n];
}
其中 dp[1]
至 dp[3]
是默认的值,用于后面转移方程的计算,转移方程为:
dp[i] = max(2 * dp[i - 2], 3 * dp[i - 3])
dp[i]
代表 n = i
时,拆分后可获得的最大乘积。
因为当 n > 4 时,n 在拆分后,最优解只包含 3 和 2,其中 2 的个数可能为 0,利用i = 2 + (i - 2)
或者 i = 3 + (i - 3)
,即 i
如果拆分出一个 2 了,则剩下的数可以根据 dp[i-2]
来直接求出, i
如果拆分出一个 3 了,则剩下的数可以根据 dp[i-3]
来直接求出,再比较两者中的最大值即可。