剑指 Offer 14- I. 剪绳子
难度中等 168
给你一根长度为 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.
public int cuttingRope(int n) {
int[] dp = new int[n + 1];
dp[2] = 1;
for(int i = 3; i < n + 1; i++){
for(int j = 2; j < i; j++){
System.out.print("dp["+i+"]="+dp[i]+",i="+i+",j="+j+",dp["+(i-j)+"]="+dp[i-j]);
dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
System.out.println(",dp["+i+"]="+dp[i]);
}
}
return dp[n];
}
解析
动态规划
这题用动态规划是比较好理解的:
我们想要求长度为 n 的绳子剪掉后的最大乘积,可以从前面比 n 小的绳子转移而来。
用一个 dp 数组记录从 0 到 n 长度的绳子剪掉后的最大乘积,也就是dp[i]表示长度为 i 的绳子剪成 m 段后的最大乘积,初始化 dp[2] = 1。
我们先把绳子剪掉第一段(长度为 j),如果只剪掉长度为 1,对最后的乘积无任何增益,所以从长度为 2 开始剪,
剪了第一段后,剩下(i - j)长度可以剪也可以不剪。如果不剪的话长度乘积即为 j _ (i - j);如果剪的话长度乘积即为 j _ dp[i - j]。取两者最大值 max(j _ (i - j), j _ dp[i - j])。
第一段长度 j 可以取的区间为[2,i),对所有 j 不同的情况取最大值,因此最终 dp[i]的转移方程为:
dp[i] = max(dp[i], max(j _ (i - j), j _ dp[i - j]))。
最后返回 dp[n]即可。
作者:edelweisskoko