版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
剪绳子
给定一根长度为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。
分析
解决这个问题有两个不同的方法解决这个问题。第一种是动态规划,需要O(n2)时间和O(n)空间。第二种是贪婪算法,只需要O(1)时间和空间。
一、动态规划
如果面试题是求一个问题的最优解(通常是求最大值和最小值),而且该问题能够分解成若干个子问题,并且子问题之间还有重叠的更小的子问题,就可以考虑用动态规划来解决这个问题。
function maxProductAfterCutting_solution1(length){
if(length<2){
return 0;
}
if(length==2){
return 1;
}
if(length==3{
return 2;
}
var products=new Array();
products[0]=0;
products[1]=1;
products[2]=2;
products[3]=3;
var max=0;
for(var i=4;i<=length;i++){
max=0;
for(var j=0;j<=Math.floor(i/2);j++){
var product=products[j]*products[i];
if(max<product){
max=product;
}
products[i]=max;
}
}
max=products[length];
detele products;
return max;
}
上述代码中,子问题从长度为4的绳子开始最优解存在数组products里面,products[0]=0到products[3]=3分别代表的是长度为0,1,2,3的绳子的长度。当数组中第i个元素表示把长度为i的绳子剪成若干段之后各段长度乘积的最大值,即f(i)。我们注意到代码中的第一个for循环变量i是顺序递增的,这意味着计算顺序是自下而上。因此在求f(i)之前,对于每一个j(0<i<j)而言,f(j)都已经求解出来了,并且结果保存在projects[j]里。为了求解f(i),我们需要求出所有可能的f(j)xf(i-j)并比较得出它们的最大值。这就是代码中第二个for循环的功能。
二、贪婪算法
贪婪算法和动态规划不一样。当我们应用贪婪算法解决问题的时候,每一步都可以做出一个贪婪的选择,基于这个选择,我们确定能够得到最优解。