剑指offer 14剪绳子

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

题目分析:典型的动态规划问题,以及贪心算法问题。

动态规划问题要从上到下分析问题,从下到上进行求解。假设一条长度为n的绳子,我们从i处分割,那么就分成了i,与m-i两段,这两段还要求其分割之后的乘积最大,所以每一步都是要求最优解。大问题能分解成小问题,每个小问题还互相相关联,这样的问题就可以使用动态规划。所以我们要想求第一处该在哪分割就要求解max(f(i)*f(n-i)),0<i<n-1;所以需要从头到尾去求f(i)。可以已知一些条件,当绳子长度为0,1时,都返回0,因为切不了。当绳子长度为2时,返回1,因为切成两半,1*1=1。当绳子长度为3时,返回2,因为可以分割为2,1与1,1,1这两种情况,那么2*1>1*1。

注意:这里没有说f(1)=0,f(2)=1,f(3)=2。为什么呢,因为我们需要判断的情况是当绳子长度为4及其以上的情况,所以,比如以4为例,可以分成1和3,此时1和3都可以不用再切开了,因为不切开时值最大,所以f(1)=1,f(3)=3,f(2)=2。还有一点就是,我们不需要从1判断到n-1,我们可以判断到n/2;因为后半段与前半段是重复的,比如f(1)*f(3)和f(3)*f(1)是相等的。

最后附上动态规划代码:动态规划的时间复杂度为O(n^2),空间复杂度为O(n),不是一个好的算法,所以接下来会写一下贪心算法的解法。

import java.util.*;
public class jianshengzi {
    public static void main(String[]args){
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int n = scanner.nextInt();
            int he = panduan(n);
            System.out.print(he);

        }

    }
    public static  int panduan(int n){
        if (n<2)
            return 0;
        if(n==2)
        return 1;
        if (n==3)
            return 2;
        int []tt = new int[n+1];
        tt[0]=0;
        //
        tt[1]=1;
        //这个tt[2]是作为子段,也就是,它可以不在分段了,所以它的值应为2而非1。
        //但是如果绳子长度就为2,必须剪一刀,所以就是1*1=1。这个要注意
        tt[2]=2;
        tt[3]=3;
        //max(tt[i]*tt[n-i])
        int max=0;
        for (int i=4;i<=n;i++)
        {
            max=0;
            //这里为什么不是<n呢,因为,比如n为4,
            //tt[i]*tt[n-i],0<i<n,i可取1,2,3
            //为tt[1]*tt[3],tt[2]*tt[2],tt[3]*tt[1]这样后面的就重复了,求一半即可,4的一半是1,2。
            for (int j=1;j<=i/2;j++)
            {
                int t=tt[j]*tt[i-j];
                if (max<t)
                {
                    max=t;
                }
                tt[i]=max;
            }
        }
        return tt[n];
    }
}

贪心算法的想法是:首先看这个长度是否大于等于5,如果大于等于5就尽量多的给它分成3,然后剩余的如果等于4就分成2。举个例子。

在代码中:我们先计算出n(长度)/3的值,这就是n包含3的个数我们记为timeof3,然后去判断n%3的值,n%3总共有3种可能,0,1,2,当为0是不考虑。当为1时,说明有4,也就是1+3=4,所以需要把3的个数减去1,然后把2的个数(timeof2)变成2。当为2时,就把2的个数变为1。最后返回3的timeof3次方与2的timeof2次方的乘积。

 

附上代码:

public static int panduan(int n)
    {
        if(n==1)
        return 0;
        if (n==2)
            return 1;
        if (n==3)
            return 2;
        if (n==4)
            return 4;
        int timeof3 = n/3;
        int timeof4=0;
        int timeof2=0;
        //余0,1,2
        //余1则有4,2*2比1*3好,余2没事,余0没事
        if (n%3==1)
        {
            timeof3--;
            timeof4++;
        }
        else if (n%3==2)
        {
            timeof2++;
        }
        if (timeof4!=0)
        {
            timeof2=2;
        }
        return (int)Math.pow(3,timeof3)*(int)Math.pow(2,timeof2);
    }

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值