题目描述
给你一根长度为 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 |
基本思路
- 动态规划:
dp[i]
表示长度为i
的绳子能得到的最大乘积,而dp[i]
是绳子在区间(0,i)
之间剪开的两部分乘积最大值。如果剪开位置在k
处,则区间分为(0,k)
和(k,i)
,第一段长度为k
,第二段长度为i-k
,而第二段存在剪与不剪的情况,若剪,则值为dp[i-k]
,否则取i-k
。综上,状态转移方程为:
$$
dp[i]=max(k * dp[i-k], k * (i-k)),~~~~2<=k<=i
$$
数学解法:
解决思路基于以下两个共识
将绳子 以相等的长度等分为多段 ,得到的乘积最大。
尽可能将绳子以长度
3
等分为多段时,乘积最大。
数学解法切分规则:
- 最优:
3
。把绳子尽可能切为多个长度为 3 的片段,留下的最后一段绳子的长度可能为 0, 1, 2 三种情况 - 次优:
2
。若最后一段绳子长度为 2 ;则保留,不再拆为 1 + 1。 - 最差:
1
。若最后一段绳子长度为 1 ;则应把一份 3 + 1 替换为 2 + 2,因为 2 × 2 > 3 × 1。
- 最优:
数学解法算法流程:
- 当n <= 3时,按照规则应不切分,但由于题目要求必须剪成m > 1段,因此必须剪出一段长度为1的绳子,即返回 n - 1。
- 当n > 3 时,求n除以3的整数部分a和余数部分b(即n=3a+b),并分为以下三种情况:
- 当b=0时,直接返回 $3^a$
- 当b=1时,要将一个1+3转换为2+2,因此返回 $3^{a-1}\times4$
- 当b=2时,返回 $3^a \times 2$
java实现
1 | // 动态规划 时复O(n²) 空复O(n) |