[Leetcode] 343. Integer Break 解题报告

来源:互联网 发布:航运货代 知乎 编辑:程序博客网 时间:2024/06/05 20:33

题目

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、动态规划:我们定义dp[i]表示i可以被分解的整数所能形成的最大乘积,那么其状态转移方程为:dp[i] = max(max(j, dp[j]) * max(i - j, dp[i - j])),其中1 <= j <= i / 2。为什么在max函数里面还需要嵌套一个max函数呢?这是因为对于正整数j,我们既可以不对它进行分解(也就是直接返回j),也可以将它分解为至少两个正整数的乘积(也就是返回dp[j])。动态规划的算法的时间复杂度是O(n^2),空间复杂度是O(n)。

2、递推法:小榕流光在博客http://blog.csdn.net/qq508618087/article/details/51289912中发现,如果n>4那么n可以一直取3直到n<=4, 这样的乘积最大。依据这个观察可以写出更加简洁和高效的递归代码。那么为什么这个观察是正确的呢?我后来看到一个很不错的证明(http://blog.csdn.net/camellhf/article/details/52733400),这里贴出来供大家参考:

1)拆出来的数只能是2和3,而不会大于3。这是因为如果拆出4,那么4可以进一步拆出2*2,最终结果不变;如果拆出5,那么5可以拆出2*3 > 5,进一步将5拆分会获得更大的值。6,7,8...之后的数我们均可以验证不会直接出现。

2)为什么尽可能地拆分为3就能获得最大的数呢?假设x = 3m + 2n,那么y = 3^m * 2^n = 3^m * 2^((x - 3m)/2)。我们对等式两边取对数:ln(y) = m * ln3 + ((x - 3m) / 2) * ln2 = x / 2 * ln2 + (ln3 - 3 / 2 * ln2) * m。其中x是一定的,并且(ln3 - 3 / 2 * ln2) > 0,所以ln(y)是关于m的增函数,也就是3的数目越大,y越大。

所以在实现的过程中,2,3,4这三种情况单独处理,其它情况就不断地拆分3,直到剩下的数在区间[2,4]之内。该算法的时间复杂度是O(n / 3) = O(n)。

代码

1、动态规划:

class Solution {public:    int integerBreak(int n) {        vector<int> dp;        dp.push_back(0);    // dp[0]        dp.push_back(1);    // dp[1]        dp.push_back(1);    // dp[2]        for(int i = 3; i <= n; ++i) {            int max_value = 1;            for(int j = 1; j <= i / 2; ++j) {                int product1 = dp[j] > j ? dp[j] : j;                int product2 = dp[i - j] > (i - j) ? dp[i - j] : (i - j);                int value = product1 * product2;                if(value > max_value) {                    max_value = value;                }            }            dp.push_back(max_value);        }        return dp[n];    }};

2、递推法:

class Solution {public:    int integerBreak(int n) {        if(n <= 2) {            return 1;        }        else if (n == 3) {            return 2;        }        int sum = 1;        while(n > 4) {            sum *= 3;            n -= 3;        }        sum *= n;        return sum;    }};