剪绳子-14
给你一根长度为 n 绳子,请把绳子剪成 m 段(m、n 都是整数,2 ≤ n ≤ 58 并且 m ≥ 2)。
每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]k[1] … k[m] 可能的最大乘积是多少?
例如当绳子的长度是 8 时,我们把它剪成长度分别为 2、3、3 的三段,此时得到最大的乘积 18。
样例
输入:8
输出:18
**思路1:**动态规划
使用动态规划的思想:
1、定义函数f(n)表示为把长度为n的绳子剪成若干段后各段长度乘积的最大值。
2、对于第一刀,我们有n-1种可能的选择,可推导出 f(n) = max{ f(i) * f(n-i) };
3、很明显这是一个从上至下的递归,但是这个递归存在很多重复的计算,所以使用至下而上的动态规划,将子问题的最优解保存。
4、注意绳子剪成 i x (n-i) 和 (n-i) x i是相同的;
5、注意不符合切割条件的输入n,以及输入为2、3长度时的结果,因为题中规定 m > 1。
class Solution {
public int integerBreak(int n) {
if(n < 2) return 0;
if(n == 2) return 1;
if(n == 3) return 2;
int[] dp = new int[n+1];
dp[0] = 0;
dp[1] = 1;
dp[2] = 2;
dp[3] = 3;
for(int i = 4; i <= n; i++){
for(int j = 1; j <= i/2; j++){
dp[i] = Math.max(dp[i], dp[j]*dp[i-j]);
}
}
return dp[n];
}
}
**思路2:**贪心
当 n >= 5 时,尽可能多地剪长度为3的绳子;当剩下的绳子长度为 4 时,把绳子剪成两段长度为 2 的绳子。
class Solution {
public int integerBreak(int n) {
if(n == 1) return 1;
if(n == 2) return 1;
if(n == 3) return 2;
if(n == 4) return 4;
int res = 1;
while(n > 4){
res *= 3;
n -= 3;
}
return res * n;
}
}