剑指offer笔记——面试题14:剪绳子

剑指offer笔记——面试题14:剪绳子


问题描述

给你一根长度为n的绳子,请把绳子剪成m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0], k[1], …, k[m]。请问k[0]×k[1]×…×k[m]可能的最大乘积是多少?
例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
个人对该题的补充解释:是把绳子减成m+1段,每段绳子的长度记为k[0], k[1], …, k[m];且每段绳子的长度k[i]均为整数(因此剪法是有限个的)

代码

#include <iostream>
#include <cmath>

/**
 * 计算把长度为length的绳子,剪成整数长度的若干段,长度乘积的最大值
 * 动态规划
 * 时间复杂度O(n^2),空间复杂度O(n)
 */
int maxProductAferCutting_solution1(int length)
{
    if(length < 2)
        return 0;
    if(length == 2)
        return 1;
    if(length == 3)
        return 2;
    /*
    products数组存放子问题的最优解,对于剪出的小段绳子,可以剪可以不剪
    当length <= 3时,剪不如不剪
    当length == 4时,剪成2,2的结果和不剪是一样的,可以按剪来处理
    当length > 4时,剪的结果比不减要大(因为做乘法的数都是大于等于1的,所以length越大,剪绳子的结果越比不剪的时候大)
    因此如果剪成的小段绳子长度大于等于4,还是要继续剪
    */
    int *products = new int[length + 1];    // 存放子问题对于总问题的最优解
    products[0] = 0;
    products[1] = 1;
    products[2] = 2;
    products[3] = 3;    // products[i]是把绳子剪成长度为i长度的绳子后,这一段绳子得到的最大乘积
    // 根据上面已知问题的最优解,继续计算当i=4,5,……,时的最优解(此时绳子一定要剪),直到最后计算出i==length时的最优解
    // 这是一个按照从下而上的顺序计算的过程
    for(int i = 4; i <= length; i++)
    {
        products[i] = 0;        // i>=4时,products[i]代表把长度为i的绳子剪成若干段之后各段长度乘积的最大值
        for(int j = 1; j <= i/2; j++)   // 由于绳子是必须要剪的,因此j从1开始,而不是从0开始;由于products[1]*products[3]和products[3]*products[1]一样,所以j到i/2为止
            if(products[j] * products[i - j] > products[i])
                products[i] = products[j] * products[i - j];
    }
    int max = products[length];
    delete[] products;      // 使用new[]申请的内存释放时要用delete[]
    return max;
}
/**
 * 计算把长度为length的绳子,剪成整数长度的若干段,长度乘积的最大值
 * 贪婪算法
 * 时间复杂度O(1),空间复杂度O(1)
 * 根据数学方法已知n>=5时尽可能多地剪长度为3的绳子,当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子,这样得到的就是全局最优解
 */
int maxProductAferCutting_solution2(int length)
{
    if(length < 2)
        return 0;
    if(length == 2)
        return 1;
    if(length == 3)
        return 2;
    int timesOf3 = length / 3;  // 尽可能多地剪去长度为3的绳子段
    if(length % 3 == 1)     // 如果先按照剪去3的方式去剪,剩余长度为1时,说明上一刀没剪时长度为4,此时不要剪这一刀,而是剪成两个长度2的绳子
        timesOf3 -= 1;
    int timesOf2 = (length - timesOf3 * 3) / 2;     // 再把绳子剪成长度为2的两段后绳子就不会再有剩余了
    return (int)(pow(3, timesOf3)) * (int)(pow(2, timesOf2));
}
int main()
{
    std::cout << maxProductAferCutting_solution1(8) << std::endl;
    std::cout << maxProductAferCutting_solution2(8) << std::endl;
    return 0;
}

运行结果

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值