给你一根长度为 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 <= n <= 58
思路
按照动规的思路来。因为长度为n,因此可能剪在位置i;剩下需要求解i和n-1这两段应该剪在什么位置。
假设dp[n]表示长度为n时的最佳相乘结果,则有dp[n]=max( dp[i]*dp[n-i] ),i=1,,,n-1。
应为dp表示子问题的最优解。所以当n≥4时,dp[2]和dp[3]至少有一个1来和他们相乘,因此有dp[2]=2,dp[3]=3。
答案
class Solution {
public:
int cuttingRope(int n) {
if(n==2)
return 1;
else if(n==3)
return 2;
vector<int> dp(n+1,0);
dp[1]=1;
dp[2]=2;
dp[3]=3;
for(int i=4;i<=n;i++){
int sub_ret=0;
for(int j=1;j<=i;j++){
if(dp[j]*dp[i-j]>sub_ret)
sub_ret=dp[j]*dp[i-j];
}
dp[i]=sub_ret;
}
return dp[n];
}
};
思路2
本答案适用于力扣
剪绳子1要把求余去掉。
贪心策略:
- 如果 n == 2,返回1,如果 n == 3,返回2,两个可以合并成n小于4的时候返回n - 1。
- 如果 n == 4,返回4。
- 如果 n > 4,分成尽可能多的长度为3的小段,每次循环长度n减去3,乘积res乘以3;最后返回时乘以小于等于4的最后一小段;每次乘法操作后记得取余就行。
- 以上2和3可以合并。
class Solution {
public:
int cuttingRope(int n) {
if(n < 4){
return n - 1;
}
unsigned int res = 1;
while(n > 4){
res = res * 3 % 1000000007;
n =n- 3;
}
return (int) (res * n % 1000000007);
}
};