剑指Offer——题14(剪绳子)

1.题目

    给你一根长度为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。

2.实现

本题采用动态规划或者贪婪算法可以实现。

2.1 动态规划实现

一开始没有思路时,可以从简单的情况开始想,试着算以下比较短的绳子是如何剪的。

  • 当n=1时,最大乘积只能为0;
  • 当n=2时,最大乘积只能为1;
  • 当n=3时,最大乘积只能为2;
  • 当n=4时,可以分为如下几种情况:1*1*1*1,1*2*1,1*3,2*2,最大乘积为4;

  往下推时,发现n≥4时,可以把问题变成几个小问题,即:如果把长度n绳子的最大乘积记为f(n),则有:f(n)=max(f(i)*f(n-1)),0<i<n。所以思路就很容易出来了:从下往上推,先算小的问题,再算大的问题,大的问题通过寻找小问题的最优组合得到。

其实这就是动态规划法,以下是动态规划法的几个特点:

  1. 求一个问题的最优解
  2. 整体问题的最优解依赖各子问题的最优解
  3. 小问题之间还有相互重叠的更小的子问题
  4. 为了避免小问题的重复求解,采用从上往下分析和从下往上求解的方法求解问题

代码实现

public class Solution14 {
    public static int  maxResultAfterCutting(int len){

        if(len<2){
            return 0;
        }
        if(len ==2){
            return 1;
        }
        if(len==3){
            return 2;
        }

        //存放0-len长度的结果
        int[] result=new int[len+1];
        result[0]=0;
        result[1]=1;
        result[2]=2;
        result[3]=3;

        for(int i=4;i<=len;i++){
            int max=0;
            for(int j=1;j<i;j++){
                result[i]=result[j] * result[i-j];
                if(result[i]>max){
                    max=result[i];
                }
                result[i]=max;

            }
        }
        return  result[len];
    }

    public static void main(String[] args) {
        int result=maxResultAfterCutting(5);
        System.out.println(result);
    }
}

2.2 贪婪算法实现

  贪婪算法依赖于数学证明,当绳子大于5时,尽量多地剪出长度为3的绳子是最优解,当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子。

public class Solution14 {

    public static int getResultAfterCutting(int len){

        if(len<2){
            return 0;
        }
        if(len ==2){
            return 1;
        }
        if(len==3){
            return 2;
        }
        //尽量切长度为3
        int timesOfThree=len/3;
        if(len-timesOfThree * 3 ==1){
            timesOfThree--;
        }
        int timesOfTwo=(len- timesOfThree*3)/2;
        return (int)(Math.pow(3,timesOfThree)*Math.pow(2,timesOfTwo));
    }

 //功能测试
   @Test
    public  void test1(){
        int result=getResultAfterCutting(8);
        System.out.println(result);
    }
//边界值测试
    @Test
    public  void test2(){
        int result=getResultAfterCutting(0);
        System.out.println(result);
    }
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值