整数拆分题

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

示例 1:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
说明: 你可以假设 n 不小于 2 且不大于 58。

 

刚看到这道题目,第一想法是认为分成多个子问题,比如正整数n,分成k和n-k,乘积为

k*(n-k),继续拆分n-k,那么求N的最大乘积可以转换为求n-k拆分的最大乘积,以此类推,

当n≥2时:

能推出状态转移方程为:dp[n] = max{k *(n-k),  k * dp[n-k]}

边界条件比较简单:dp[0] = dp[1] = 0

c++实现:

int integerBreak(int n) 
{
    vector <int> dp(n + 1);
    for (int i = 2; i <= n; i++)
    {
        int curMax = 0;
        for (int j = 1; j < i; j++)
        {
            curMax = max(curMax, max(j * (i - j), j * dp[i - j]));
        }
        dp[i] = curMax;
    }
    return dp[n];
}

 

我在试完这种解法之后,觉得这道题目肯定还有更简单效率更高的数学解法,于是在草稿纸上找了几个数手动拆分,然后果然在里面发现了一些规律。

下面列出一些最大值的拆分项:

3: 1 * 2

4: 2 * 2

5: 2 * 3

6: 3 * 3  

7: 3 * 4  or  2 * 2 * 3

8: 3 * 3 * 2

9: 3 * 3 * 3

10:3 * 3 * 4

11:3 * 4 * 4

...

       如果要求N的拆分后乘积最大,是不是要穷举所有拆分的个数中最大的然后取最大的,每个个数对应的组合数量太大,这样计算起来时间吃不消,我观察到不管拆分成多少数量,每一个数的大小相差都不会超过1,我大胆的猜测了一下,假设正整数为n,数量为i,那最大的拆分项肯定有n/i(即平均值),考虑到会除不尽的情况,余数n%i肯定小于n,可以说小于n / 2 + 1,再平均分配给n%i个数,那么最大乘积计算方法就可以:max(n, i) = ((n / i)^ {i - n % i} ) * ( (n / i + 1)^{n % i})

简单解释一下:就是有i - n % i 个数为 n / i,有n%i个数为n/i + 1,这样组合就是每个拆分数量中的最大乘积值。那么写出代码就很简单了。

int integerBreak(int n) 
{
    int max_value = 0;
    int tmp = 0;
    for (int i = 2; i <= n / 2 + 1; i++)
    {
        tmp = pow((n / i), (i - n % i)) * pow(n / i + 1, n % i);
        max_value = max_value > tmp ? max_value : tmp;
    }

    return max_value;
}

       我认为i的范围是可以缩小的,就是说可以推理出一个方程计算正整数n拆分成i个数时有最大乘积值。这个值可以推导出:

i = n / 3 (n>5)

i = 2 (n>1 && n<=5),

      这样就可以在O(1)直接计算结果。

int integerBreak(int n) 
{
    int max_value = 0;

    if(n > 1 && n < 6)
    {
        max_value = pow(n / 2, (2 - n % 2)) * pow(n / 3 + 1, n %  2);
    }
    else if(n > 5)
    {
        max_value = pow(3, (n / 3 - n % (n / 3))) * pow(4, n % (n / 3));
    }

    return max_value;
}

 

leetcode官网这道题解也有相应的数学推导和动态优化,我觉得应该是相通的。改天可以去深入推导一下。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值