原题
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m]
。请问 k[0]*k[1]*...*k[m]
可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例 1:1
2
3输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:1
2
3输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:
- 2 <= n <= 58
原题url:https://leetcode-cn.com/problems/jian-sheng-zi-lcof
解题
动态规划 DP
我们想想,本题要求是计算 n 被分成 m 份后,相乘最大的结果,这比较明显可以看出是需要求一定要求下的最优解,那么如果能求出局部最优解的话,也能求出方便求出最终最优解。讲白了,就是一个个试,但需要保证需要将所有情况都计算过,且不要重复计算。
那这就要利用动态规划的思想了,从初始情况开始,一步步递推。假设绳子长度为 x ,其最大乘积为 f(x),则有:1
2
3
4
5
6
7f(2) = 1; (1 * 1)
f(3) = 2; (1 * 2)
f(4) = 4; (2 * 2)
f(5) = 6; (3 * 2)
f(6) = 9; (3 * 3)
f(7) = 12; (3 * 2 * 2 = 3 * f(4))
f(8) = 18; (3 * 3 * 2 = f(6) * 2 = 3 * f(5))
自己先试着写出初始的情况,然后从中找出规律:
- 长度1、2、3,并没有继续分隔的必要,其作为整体,直接参与计算应该就是最大的数字了。
- 长度4,分隔成2、2是比较合理的。
- 当长度越长,被分隔成的数量越多时,其实可以想象成将其中多段合并成1段,最后都是可以当做分隔成2段来计算的。
因此,根据上面总结出来的规律,我们应该是需要从小开始计算,并将中间结果保留,因此可以用一个数组进行存储。
我们来看看代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class Solution {
public int cuttingRope(int n) {
if (n == 2) {
return 1;
}
// 记录计算结果,第2位代表长度为2的绳子,其最大乘积
int[] result = new int[n + 1];
result[1] = 1;
result[2] = 1;
for (int i = 3; i <= n; i++) {
// 默认初始值就是剪成两段:1 和 i-1,所以最大乘积是 i-1
result[i] = i - 1;
for (int j = 1; j <= i / 2; j++) {
int x = Math.max(result[i - j], i - j);
int y = Math.max(result[j], j);
result[i] = Math.max(x * y, result[i]);
}
}
return result[n];
}
}
提交OK。
数学推导的极致优化
这个解法,我也是看了别人的解析才知道的,通过代码提交发现结论确实是正确的,但其中的推导过程我也没有看懂,看看原文:
接下来我们看看代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class Solution {
public int cuttingRope(int n) {
if (n == 2) {
return 1;
}
if (n == 3) {
return 2;
}
// 可以被3分成几段
int count = n / 3;
// 剩余的数字
int remain = n % 3;
// 如果没有剩余的
if (remain == 0) {
// 直接计算当前的值
return (int) Math.pow(3, count);
}
// 如果剩1,则和原本的一个3,重新拆分成2和2,因为2 * 2 > 3 * 1
if (remain == 1) {
return (int) Math.pow(3, count - 1) * 2 * 2;
}
// 如果剩2,则正常乘
return (int) Math.pow(3, count) * 2;
}
}
提交OK。
总结
以上就是这道题目我的解答过程了,不知道大家是否理解了。这道题的一般解法是动态规划,优化时可以尝试找规律,数学推导出其中当然是最快的,但这需要一定的功底。
有兴趣的话可以访问我的博客或者关注我的公众号、头条号,说不定会有意外的惊喜。
公众号:健程之道