题目

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.

Example 1:

  1. Input: 2
  2. Output: 1
  3. Explanation: 2 = 1 + 1, 1 × 1 = 1.

Example 2:

  1. Input: 10
  2. Output: 36
  3. Explanation: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36.

Note: You may assume that n is not less than 2 and not larger than 58.


题意

将一个正整数拆成至少两个正整数的和,使得拆分出来的正整数之积最大。

思路

经验告诉我们,当一个正整数被拆成n个整数时,积最大时这n个整数应该相等(或相近),如10拆成2个整数时,55最大,拆成3个时,334最大,拆成4个时,2233最大…所以我们只要从n=2开始递增,求出积变化情况的极大值即可。

打一张表找一下规律:

正整数n 最大积
2 1*1
3 1*2
4 2*2
5 3*2
6 3*3
7 3*4
8 332
9 333
10 334
11 333*2
12 333*3
13 333*4

可以看到当n大于4时,最大积的情况都是将n拆成尽可能多的3,且除3外只能有一个2或者一个4。该规律的证明可参考《平分一个数,使得各份相乘所得到的积最大》

也可以使用动态规划:dp[i]代表正整数i拆分后能得到的最大积,i可以被拆分为2个或更多的整数,拆分为两个时得到的积为j(i-j),拆分为多个时可得到的积为jdp[i-j]。状态转移方程为:
0343. Integer Break (M) - 图1


代码实现

Java

极大值

  1. class Solution {
  2. public int integerBreak(int n) {
  3. int pre = 0;
  4. int count = 2;
  5. while (count <= n) {
  6. int num = n / count;
  7. int remain = n % count; // 存在余数时,要将余数中的每一个1都分配到num上以求积最大化
  8. int cur = (int) Math.pow(num, (count - remain)) * (int) Math.pow((num + 1), remain);
  9. if (cur >= pre) {
  10. pre = cur;
  11. } else {
  12. return pre;
  13. }
  14. count++;
  15. }
  16. return pre;
  17. }
  18. }

找规律

  1. class Solution {
  2. public int integerBreak(int n) {
  3. if (n == 2 || n == 3) {
  4. return n - 1;
  5. }
  6. int cnt3 = n / 3;
  7. int remain = n % 3;
  8. if (remain == 1) {
  9. return (int) Math.pow(3, cnt3 - 1) * 4;
  10. } else {
  11. return (int) Math.pow(3, cnt3) * (remain == 2 ? 2 : 1);
  12. }
  13. }
  14. }

动态规划

  1. class Solution {
  2. public int integerBreak(int n) {
  3. int[] dp = new int[n + 1];
  4. Arrays.fill(dp, 1);
  5. for (int i = 3; i <= n; i++) {
  6. for (int j = 1; j < i; j++) {
  7. dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
  8. }
  9. }
  10. return dp[n];
  11. }
  12. }

参考