剑指Offer 面试题14:剪绳子
原题描述:
面试题14:剪绳子
给你一根长度为n的绳子,请把绳子剪成m段(m,n都是大于1 的整数)。每段绳子长度的可能最大乘积是多少。
分析问题的时候,很容易就可以得出这个问题的递归式:记长度为n的最大乘积为f(n),易知f(n)=max{ f(i)*f(n-i) },其中0<i<n。但是递归求解过程中,有很多子问题会重复求解,效率不高。这种子问题重叠较多的递归式,适合采用动态规划的方式求解。这儿就是使用自底向上的方式求解问题的,采用额外的存储空间,记录子问题的解,后续就可以直接使用,提高时间效率。动态规划实际上就是用空间效率换区时间效率的一种做法。
首先,计算出最基本的几个子问题的解,然后根据递归式向上求解较大问题,重要的是,过程中的解都得记录下来。
public static int maxProductAfterCutting(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;
//自底向上开始求解
int max=0;
for(int i=4;i<=len;i++){
max=0;
for(int j=1;j<=i/2;j++){
int tempResult=result[j]*result[i-j];
if(max<tempResult)
max=tempResult;
result[i]=max;
}
}
max=result[len];
return max;
}
public static int maxProductWithGreedy(int len){
if(len<2)
return 0;
if(len==2)
return 1;
if(len==3)
return 2;
//啥也不管,先尽可能减去长度为3的段
int timeOfThree=len/3;
//判断还剩下多少,再进行处理
if(len-timeOfThree*3==1)
timeOfThree-=1;
int timeOfTwo=(len-timeOfThree*3)/2;
return (int) ((Math.pow(3, timeOfThree))*(Math.pow(2, timeOfTwo)));
}
动态规划以及贪心算法在《算法导论》 16、17章有专门讲解,看完这两章,再看这道面试题算是入门级别的。