14.减绳子
1. DP 求解
假设 res[n] 代表长度为 n 的绳子的最大乘积,那么 res[n] = max(res[n-i] * res[i]),其中(1<=i<n)
特别的有一些特殊值:
res[0] = 0; //不存在
res[1] = 1;
res[2] = 2; //在长度为2时该绳子就不应该被分割了,分割会更小
res[3] = 3; //在长度为3时不应该被分割,分割会更小
代码
1 | class Solution { |
2. 贪心法
可以通过数学方法证明如下推论:
- 推论一:合理的切分方案可以带来更大的乘积
设一根绳子长度为n(n>1),切分为两段 n = n1+n2,切分为三段 n = n1+n2+n3。根据经验推测,三段的乘积往往更大,即往往有 n1n2n3 > n1n2。
当然也存在反例,比如两段 6 =3+3 和三段 6 =2+2+2,则有 3×3 > 2×2×2
- 推论二:若切分方案合理,绳子切分越多,乘积越大
总体上看,貌似长绳子切分为越多,但其实到某个长度分界点后,乘积到达最大值就不再切分了。
- 推论三:为使乘积最大,只有长度为2和3的绳子不应再切分,切3比2更优
代码
1 | class Solution { |
1.DP的缺陷(不可用)
这个题和剪绳子I一样的描述,就是数据范围变大了。剪绳子可以用动态规划或者贪心做,这道题对于使用DP难度就增大了一些,因为数据范围变得比较大时,long已经不足以去存储中间结果的状态,但是由于DP做法是枚举各种剪的情况然后取最大值,因此只能通过使用BigInteger的方法去做,这点评论区已经有人给出了解答。
那么这个题范围变大的本意是想让我们使用贪心算法能更好的求解(毕竟BigInteger使用起来麻烦,贪心没有数据溢出的问题,它是找当下的最优解,不需要比较,中间结果可以直接取模)。
2. 贪心法(可用)
我们首先考虑对于一段长n的绳子,我们可以切出的结果包含什么?
1 会包含吗? 不会,因为1 * (k - 1) < k, 只要把1和任何一个其他的片段组合在一起就有个更大的值
2 可以
3 可以
4 可以吗? 它拆成两个2的效果和本身一样,因此也不考虑
5 以上可以吗? 不可以,这些绳子必须拆,因为总有一种拆法比不拆更优,比如拆成 k / 2 和 k - k / 2
综上, 最后的结果只包含2和3(当然当总长度为2和3时单独处理), 那么很显然n >= 5时, 3*(n - 3) >= 2 * (n - 2) ,因此我们优先拆成3,最后剩余的拆成2。最后的结果一定是由若干个3和1或2个2组成.
代码
1 | class Solution { |
3.快速幂解(基于贪心法)
1 | class Solution { |
快速幂算法:https://blog.csdn.net/qq_19782019/article/details/85621386