题目描述
代码语言:javascript复制给你一根长度为 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。
来源:https://leetcode.cn/problems/jian-sheng-zi-lcof
示例1:
代码语言:javascript复制输入: 2
输出: 1
解释: 2 = 1 1, 1 × 1 = 1
示例2:
代码语言:javascript复制输入: 10
输出: 36
解释: 10 = 3 3 4, 3 × 3 × 4 = 36
提示:
代码语言:javascript复制2 <= n <= 58
解题分析
我们从题目中看到,长度N的绳子切割后,分段值乘积最大的结果其实与较短的结果相关,比如分成2段,可以是1和6,2和5以及3和4,所以如果考虑乘积,我们可以考虑动态规划的思想,把每段的最大值存储下来。
代码语言:javascript复制int[] dp = new int[n 1];
//dp[i]表示长度为i的切割段的最大乘积,其中:
dp[0] = 0; //不能分段
dp[1] = 0; //不能分段,记为0
dp[2] = 1; //只能分成2段1和1, 乘积为1 * 1 = 1
通过2层循环解决,
1、外层循环:因为dp[0]、dp[1]和dp[2]的值都已知,不是0就是1,所以,求乘积,我们外层从dp[3]开始。
2、内存循环:比对当前分成2段 (i -j) * j的值,和其他分段的最大乘积的值dp[i-j][j],两者之间的值,取大值。
代码语言:javascript复制 dp[i] = Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
有了这个思路,我们来写出一个dp解法:
方法1
代码语言:javascript复制class Solution {
public int cuttingRope(int n) {
int[] dp = new int[n 1];
dp[0] = 0; // 不能切断
dp[1] = 0; // 不能切断
dp[2] = 1; // 只能是1 * 1 = 1
for (int i = 3; i <= n; i ) {
for(int j = 2; j <i; j ) {
dp[i] = Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
}
}
return dp[n];
}
}
由于分段有一定的对称性,比如N = 7, 分成2段,1和6,2和5,3和4, 4和3,5和2,6和1,所以可以看出,有一定的对称性。所以,内循环的范围可以只到中间值:
代码语言:javascript复制for(int j = 2; j <=(i j) /2; j ) {
... ...
}
调整后的代码:
代码语言:javascript复制class Solution {
public int cuttingRope(int n) {
int[] dp = new int[n 1];
dp[0] = 0; // 不能切断
dp[1] = 0; // 不能切断
dp[2] = 1; // 只能是1 * 1 = 1
for (int i = 3; i <= n; i ) {
for(int j = 2; j <=(i j) /2; j ) {
dp[i] = Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
}
}
return dp[n];
}
}
做完了14-I,我们发现还有14-II。
题目描述:剑指offer 14-II. 剪绳子II
代码语言:javascript复制给你一根长度为 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。
答案需要取模 1e9 7(1000000007),
如计算初始结果为:1000000008,请返回 1。
来源:https://leetcode.cn/problems/jian-sheng-zi-ii-lcof
示例1:
代码语言:javascript复制输入: 2
输出: 1
解释: 2 = 1 1, 1 × 1 = 1
示例2:
代码语言:javascript复制输入: 10
输出: 36
解释: 10 = 3 3 4, 3 × 3 × 4 = 36
提示:
代码语言:javascript复制2 <= n <= 1000
这个14-II与14-I的区别是对于较大的数字需要取模, 如:
代码语言:javascript复制答案需要取模 1e9 7(1000000007),
如计算初始结果为:1000000008,请返回 1
大数计算,我们可以使用java.math.BigInteger来替代int,如:
代码语言:javascript复制import java.math.BigInteger;
import java.util.Arrays;
class Solution {
public int cuttingRope(int n) {
BigInteger[] dp = new BigInteger[n 1];
Arrays.fill(dp, BigInteger.valueOf(0));
dp[0] = BigInteger.valueOf(0); // 不能切断
dp[1] = BigInteger.valueOf(0); // 不能切断
dp[2] = BigInteger.valueOf(1); // 只能是1 * 1 = 1
for (int i = 3; i <= n; i ) {
for (int j = 2; j <= (i j) / 2; j ) {
dp[i] = dp[i].max(BigInteger.valueOf(j * (i - j))).max(dp[i - j].multiply(BigInteger.valueOf(j)));
}
}
return dp[n].mod(BigInteger.valueOf(1000000007)).intValue();
}
}