343. Integer Break

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.

这一题是给一个数字n,将n拆分为k(k >= 2)个数字, 使得n = x1 + x2 + ... + xk

然后计算x1 * x2 * ... * xk,使得积最大


我们来找递推关系

设f(n)为最佳的拆分选择,那么f(n) = max{f(n-x) * x}, 0<x<n

那么我们的动态规划程序可以如下:

int integerBreak(int n) {
       int save[59];      //保存数据

        save[1] = 1;
save[2] = 1;     //第一个数
for (int i = 3; i <= n; i++){
save[i] = 0;
for (int j = 1; j < i; j++)   
save[i] = max(save[i], (i-j) * save[j]);
}  
return save[n];
}

这个代码看似正确,实际上其中含着一个致命的bug

我们容易知道,save[2] = 1 < 2, save[3] = 2 < 3,这两个数的拆分后的积是小于自己的

那么,利用到这两个值的数就会出错。例如,我们容易知道 5 = 2 + 3, save[5] = 2 * 3 = 6是最佳选择。如果按照上面代码来计算的话,就会出现

5 = 2 + 3, save[5] = 2 * save[3] = 2 * 2 = 4,结果显然是错误的。

如何解决这个问题呢?有一个办法。我们令 save[2] = 2, save[3] = 3 就好。

修改后代码如下:

int integerBreak(int n) {
        int save[59];
if (n <= 3) return n-1;  //n小于3直接返回
save[1] = 1;      //辅助用
save[2] = 2;
save[3] = 3;
for (int i = 4; i <= n; i++){
save[i] = 0;
for (int j = 1; j < i; j++)
save[i] = max(save[i], (i-j) * save[j]);
}  

return save[n];
}

当然这样做之后结果是正确的,但是效率较低,时间复杂度为O(n^2),没有更好的办法呢?

我们通过观察答案了解到,实际上所有的数,经过最佳拆分之后,拆分出的数要么是2,要么是3,要么是4

就是说,所有数的最佳拆分,都是由2、3、4组成的

那么我们第二个迭代就可以修改

for (int j = 2; j <= 4 && j < i; j++)

    save[i] = max(save[i], j * save[i - j]);

如此一来,时间复杂度就变为O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值