剪绳子

一、需求

  • 给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[1],...,k[m]。请问k[1]x...xk[m]可能的最大乘积是多少?
  • 例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

二、测试样例

  • 输入样例
8
  • 输出样例
18

三、动态规划法

3.1  思路分析 

  1. 定义数组dp,dp[n]表示绳子长度为n时,分割后每一段乘积的最大值;
  2. n == 2和n == 3时,只能切一刀,最大乘积分别为1和2;
  3. n == 4时,若切一刀,有两种情况:1和3及2和2,这个时候就没有必要对3再切了,也没有必要对2切了,最大乘积就是4;
  4. n == 5时,若切一刀,有1和4,2和3,3和2,4和1,只相当于两种情况,也没有必要再切了。

所以当n >= 4的时候,如果切下来有长度为2或3的段时,就没有必要再切了,用数组表示就是

dp[1] = 1,dp[2] = 2,dp[3] = 3,这里一定要上述步骤2区分开,这里是n >= 4时的情况,在这种情况下,对绳子切割,出现了长度为2或3的段,这时候就不用再对长度为2或3的段切割了,直接返回它们的长度即可。

3.2  代码实现

public int cutRope(int target) {
        int[] dp = new int[target+1];
        if(target == 2) {
            return 1;
        }
        if(target == 3) {
            return 2;
        }
        dp[1] = 1;
        dp[2] = 2;
        dp[3] = 3;
        int res = 0;
        for(int i = 4; i <= target; i++) {
            for(int j = 1; j <= i/2; j++) {
                res = Math.max(j*dp[i - j],res);
            }
            dp[i] = res;
        }
        return dp[target];
    }

3.3  复杂度分析

  1. 时间复杂度为O(n^2);
  2. 空间复杂度为O(n);

四、数学推导法

4.1  思路分析

  1. 这里需要利用一个推论,①将绳子以相等的长度分为多段,则得到的乘积最大;
  2. 根据推论①可以推导出当等分的长度为 3 时可获得最大乘积,具体推导过程可见:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/mian-shi-ti-14-i-jian-sheng-zi-tan-xin-si-xiang-by/
  3. 在 2 的基础上,将一段绳子尽可能按照每一段为 3 的长度划分,那么这段绳子最后剩下的长度可能为0、1、2;
  4. 如果剩下的长度为 0,说明正好全部都是 3 等分了;如果剩下的长度为 1,这时候,我们就拿出一个 3 ,和这个 1 用 2 和 2来代替;如果剩下的长度为 2 ,那保持不变;

4.2  代码实现

class Solution {
    public int cuttingRope(int n) {
        if(n <= 3) return n - 1;
        int a = n / 3;
        int b = n % 3;
        if(b == 0) return (int)Math.pow(3, a);
        if(b == 1) return (int)Math.pow(3, a - 1) * 4;
        return (int)Math.pow(3, a) * 2;
    }
}

4.3  复杂度分析

  • 时间复杂度为O(1);
  • 空间复杂度为O(1);

五、贪心算法

5.1  思路分析

  1. 经过证明,当绳子按 3 等分时可获得最大乘积,特殊情况:①当n == 2 或 3 无法进行 3 等分,②当n == 4时,可以进行 3 等分,但是没有必要,因为最大为 4;
  2. 于是当绳子长度大于 5 时,我们开始进行 3 等分,经过枚举归纳,3 等分后剩余的绳子的长度为 2 , 3 , 4中的一个;
  3. 因此,最后的结果,只需要将等分的总长度乘以剩余绳子的长度即可;

5.2  代码实现

class Solution {
    public int cuttingRope(int n) {
        if(n <= 3) return n - 1;
        if(n == 4) return 4;
        int res = 1;
        //当绳子长度大于4时,按3等分,剩下的长度只能为2,3,4,而2,3,4无须再分
        while(n > 4) {
            res = res * 3;
            n = n - 3;
        }
        return res * n;
    }
}

5.3  复杂度分析

  • 时间复杂度为O(n);
  • 空间复杂度为O(1);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值