14. 剪绳子(剑指 Offer 题解Java版)

14. 剪绳子

1、 题目链接

Leetcode

2、题目描述

       把一根绳子剪成多段,并且使得每段的长度乘积最大。

n = 2
return 1 (2 = 1 + 1)

n = 10
return 36 (10 = 3 + 3 + 4)

3、解题思路

3.1贪心

        尽可能多剪长度为 3 的绳子,并且不允许有长度为 1 的绳子出现。如果出现了,就从已经切好长度为 3 的绳子中拿出一段与长度为 1 的绳子重新组合,把它们切成两段长度为 2 的绳子。

        证明:当 n >= 5 时,3(n - 3) - n = 2n - 9 > 0,且 2(n - 2) - n = n - 4 > 0。因此在 n >= 5 的情况下,将绳子剪成一段为 2 或者 3,得到的乘积会更大。又因为 3(n - 3) - 2(n - 2) = n - 5 >= 0,所以剪成一段长度为 3 比长度为 2 得到的乘积更大。

        分析:抽象一下题目就是把n分成很多个数字,要求这些数字的乘积最大,问你最大的乘积是多少?
先找一下规律
* 先举几个例子,可以看出规律来。

* 4 : 2 * 2

* 5 : 2 * 3

* 6 : 3 * 3

* 7 : 2 * 2 * 3

* 8 : 2 * 3 * 3

* 9 : 3 * 3 * 3

* 10:2 * 2 * 3 * 3

* 11:2 * 3 * 3 * 3

* 12:3 * 3 * 3 * 3

* 13:2 * 2 * 3 * 3 * 3

我们发现分解的数字中只有2和3,这样的话乘积才能最大,相对于2,肯定是取3更加的好,所以是能取3的时候一定取3,

当n%3 == 0时,也就是全都是3的时候,这个时候乘积肯定最大

当n%3 == 1时,注意1 * 3……* 3肯定没有2 * 2 * 3 …… * 3大,所以我们应该把一个3拿出来和剩下的那个1组成22的形式

当n%3==2时,2 * 3 * …… * 3的形式乘积最大

时间复杂度:O(1)

package 剪绳子;
/*
作者     :XiangLin
创建时间 :18/03/2020 20:02
文件     :cutRope.java
IDE      :IntelliJ IDEA
*/

public class cutRope {
    public int integerBreak(int n){
        if(n<2)
            return 0;
        if (n == 2)
            return 1;
        if (n == 3)
            return 2;

        int timesOf3 = n / 3;
        if (n - timesOf3 * 3 == 1)
            timesOf3 --;
        int timesOf2 = (n - timesOf3 * 3)/2;

        return (int) (Math.pow(3,timesOf3)) * (int)(Math.pow(2,timesOf2));
    }

    public static void main(String[] args) {
        cutRope c = new cutRope();
        int n = 9;
        System.out.println(c.integerBreak(n));
    }
}

在这里插入图片描述

3.2动态规划

        时间复杂度O(n^2);空间复杂度:O(n)。

        定义函数f(n)为把长度为n的绳子剪成若干段后各段长度乘积的最大值。在剪第一刀时,有n-1种选择,即剪出的第一段绳子长度可能为1,2,3,…,n-1。因此 f ( n ) = max( f ( i ) * f ( n - i ) ),其中0<i<n。
   
        例如:绳子最初的长度为10,我们可以把绳子剪成长度分别为4和6的两段,也就是f(4)和f(6)都是f(10)的子问题。接下来分别求解这两个子问题。我们可以把长度为4的绳子剪成均为2的2段,即f(2)是f(4)的子问题。同样,我们也可以把长度为6的绳子剪成长度分别为2和4的两段,即f(2)和f(4)都是f(6)的子问题。我们注意到f(2)是f(4)和f(6)的公共的更小的子问题。

package 剪绳子;
/*
作者     :XiangLin
创建时间 :18/03/2020 20:42
文件     :cutRope1.java
IDE      :IntelliJ IDEA
*/
// 动态规划
public class cutRope1 {
    public int maxProductAfterCuttingSolution1(int n){
        if (n < 2)
            return 0;
        if (n == 2)
            return 1;
        if (n == 3)
            return 2;
        int[] products = new int[n + 1];
        // 这里设置的0,1,2,3位置上的数是为了便于计算。
        // 当i大于等于4时,数组中第i个元素表示把长度为i的绳子剪成若干段之后各段长度乘积的最大值
        products[0] = 0;
        products[1] = 1;
        products[2] = 2;
        products[3] = 3;
        int max;
        for (int i = 4; i <= n; i++){
            max = 0;
            for (int j = 1; j <= i/2; j++){
                 int product = products[j] * products[i - j];
                if (max < product){
                    max = product;
                    products[i] = max;
                }
            }
        }
        return products[n];
    }

    public static void main(String[] args) {
        cutRope1 c = new cutRope1();
        int n =9;
        System.out.println(c.maxProductAfterCuttingSolution1(n));
    }
}

在这里插入图片描述
个人微信公众号,专注于学习资源、笔记分享,欢迎关注。我们一起成长,一起学习。一直纯真着,善良着,温情地热爱生活,,如果觉得有点用的话,请不要吝啬你手中点赞的权力,谢谢我亲爱的读者朋友
五角钱的程序员,专注于学习资源、笔记分享。
Everyone wants to stand on top of the mountain, but all the happiness and growth occurs while you’re climbing.
每个人都想站在山顶上,但所有的幸福与成长都发生在攀登的过程中。

XiangLin
2020年3月18日于重庆城口
好好学习,天天向上,终有所获

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值