题目描述
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
思路
第一次做这个题的时候其实走入了歧途,跟着某个大佬利用数学直接整明如何剪,现在想想我们刷题就是为了遇见某个问题能有通用的解决方法解决了问题,再去寻求更高效的方法。
本题其实很明显的跟跳台阶有很大的相似之处,因此也可以尝试用递归或者动态规划来做。
首先是递归。递归就要找到递归的返回条件。
长度为2的绳子,只有一种剪的方法,即1+1(因为不能不剪),乘积为1
长度为3的绳子,也只有一种剪法,即1+2(和2+1是一样的),乘积为2
长度为4的绳子,就有2种了,即1+3和2+2,大乘积为4
长度为5的绳子,也有2种,即1+4和2+3,大乘积为6
上面要注意的是,2和3是非常特殊的,作为总长度的时候,分开后的乘积是比本身长度小的,但是不得不分开;但是作为小段长度,我们可以选择不分开,取本身。所以我们就将递归返回边界定为n<=3,满足直接返回本身
实现:
class Solution {
public:
int cut(int n)
{
if (n<=3) return n;
int ret=0;
for (int i=1;i<n;i++)
ret= max(ret,i*cut(n-i));
return ret;
}
int cutRope(int number) {
if (number==2) return 1;
if (number==3) return 2;
return cut(number);
}
};
最大的n输入为30,通不过题目给的62。原因在于递归过程中在不断计算cut(n-i),如果能想办法将先计算过的存储起来,就能减少后续计算的时间了,即动态规划的思路。
动态规划:
class Solution {
public:
int cutRope(int number) {
if (number==2) return 1;
if (number==3) return 2;
vector<int> v(number+1,0);
//这里也是类似刚刚的递归返回条件分析,
//2,3作为总长度和小段长度的处理方式是不一样的
for (int i=1;i<4;i++)
v[i]=i;
for (int i=1;i<=number;i++)
{
for (int j=1;j<i;j++)
//计算(1,i-1),(2,i-2)...的最大值作为i分段的目标结果,思路跟递归是一样的,只是这里都存起来了
{
v[i]=max(v[i],j*v[i-j]);
}
}
return v[number];
}
};