剪绳子
题目描述:给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
解题思路:
思路一:动态规划
我们根据题目要求知道,这条绳子是必须要剪的,当绳子长度小于2时就不能剪,必须返回,当剩余绳子长度为2时,如果我们再继续剪一刀就会变成1和1,这样他们的乘积就是1,小于原来长度2,如果剩余绳子长度为3时,如果再剪一刀,就会变成1和2,他们的乘积就是2,小于原来长度3,所以,当剩余绳子长度小于4时,我们就不能继续剪。假设一刀将绳子剪为i和n-i,那么最大乘积就是F(n)=F(i)*F(n-i),F(x)代表的是,绳子长度为x时的最大乘积。但是这个式子是一个从上到下的递归式,其中包含大量的重复计算,所以我们需要从下往上记录,我们定义一个数组cnt用来记录当绳长为下标长度时的最大乘积(值)。
class Solution {
public:
int cuttingRope(int n) {
if(n<4)return n-1;
vector<int>cnt(n+1,0);//多开一个空间,用来存放绳子长度为0的情况
//下面这些不是说当绳子长度为0,1,2,3时他们的最大乘积是0,1,2,3
//而是,指如果绳子剩下1,2,3后他们就不在继续剪了,假如剩下绳长为3时,如果在继续剪一刀,那么就会变成1和2,1和2的乘积是2小于3,所以当绳长剩余0,1,2,3时就不剪了。
cnt[1]=1;
cnt[2]=2;
cnt[3]=3;
for(int i=4;i<=n;++i)
{
int maxVal=0;
for(int j=1;j<=i/2;++j)//代表的是剩余绳长从4开始,那么可以继续剪,最开始剪去长度为1的绳子,算出最大乘积,然后在剪去J++de绳子,再继续算最大乘积。
//为什么j<i/2呢?是因为剪去一半以后再继续剪,就会和之前的结果是一样的。
{
maxVal=max(maxVal,cnt[j]*cnt[i-j]);
}
cnt[i]=maxVal;
}
return cnt[n];
}
};
思路二:找规律法
我们发现当绳子分的长度中3的个数更多的时候,最后的结果就会更大。综上有以下代码:
class Solution {
public:
int cuttingRope(int n) {
if(n<4)return n-1;
int a=n/3,b=n%3;
if(b==0)return a=pow(3,a);
if(b==1)return a=pow(3,a-1)*4;
if(b==2)return a=pow(3,a)*2;
return a;
}
};