面试题14:剪绳子
题目:给你一根长度为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。
#include <iostream>
#include <cmath>
using namespace std;
/**
* 动态规划版本
**/
int maxProductAfterCutting_solution(int length) {
if(length<2) return 0;
if(length==2) return 1;
if(length==3) return 2;
int *products = new int[length+1];
products[0]=0;
products[1]=1;
products[2]=2;
products[3]=3;
int max=0;
for(int i=4;i<=length;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;
}
}
max=products[length];
delete[] products;
return max;
}
/**
* 扎实的数学功底ヾ(≧▽≦*)o
* 贪婪算法版本:首先,当n>=5的时候,我们可以证明 2(n-2)>n 并且 3(n-3)>n. 也就是说,
* 当绳子剩下的长度大于或者等于5的时候,我们就把它剪成长度为3或者2的绳子段。另外,
* 当n>=5时,3(n-3)>2(n-2),因此我们应该尽可能地多剪长度为3的绳子段。
*/
int maxProductAfterCutting_solution2(int length) {
if(length<2) return 0;
if(length==2) return 1;
if(length==3) return 2;
// 尽可能多地剪去长度为3的绳子段
int timesOf3 = length/3;
// 当绳子最后剩下的长度为4的时候,不能再剪去长度为3的绳子段。
// 此时更好的方法是把绳子剪成长度为2的两段,因为 2x2>3x1
if(length-timesOf3*3==1) timesOf3-=1;
int timesOf2=(length-timesOf3*3)/2;
return (int)(pow(3, timesOf3)) * (int)(pow(2, timesOf2));
}
int main() {
printf("%d", maxProductAfterCutting_solution2(4));
return 0;
}