题目
给你一根长度为 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:
输入: 2 输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:
输入: 10 输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:
2 <= n <= 58
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof
解题思路
解题思路引用自作者:jyd
-
若切分方案合理,绳子段切分的越多,乘积越大。
- 总体上看,貌似长绳子切分为越多段乘积越大,但其实到某个长度分界点后,乘积到达最大值,就不应再切分了。
-
问题转化:是否有优先级最高的长度 xx 存在?若有,则应该尽可能把绳子以 xx 长度切为多段,以获取最大乘积。
-
为使乘积最大,只有长度为 2 和 3 的绳子不应再切分,且 3 比 2 更优 (详情见下表)
算法流程
-
贪心规则:根据以上分析,得出以下规则。
- 最高优先级: 3 。把绳子尽可能切为多个长度为 3 的片段,留下的最后一段绳子的长度可能为 0, 1 , 2 三种情况。
- 次高优先级: 2 。若最后一段绳子长度为 2,则保留,不再拆为 1+1 。
- 最低优先级: 1。 若最后一段绳子长度为 1;则应把最后的 3 + 1 替换为 2 + 2,因为 2 × 2 > 3 × 1。
-
算法流程( n = 3a + b )
- 当 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} ×4
- 当 b = 2 时,返回 3^a ×2。
写法一:代码
–执行用时:0 ms --内存消耗:1.9 MB
func cuttingRope(n int) int {
if n==1||n==2{
return 1
}
if n==3{
return 2
}
a:=n/3//整数部分
b:=n%3//余数部分
if b==0{
return int(math.Pow(3.0,float64(a)))
}
if b==1{
return int(math.Pow(3.0,float64(a)-1))*4
}
//b==2
return int(math.Pow(3.0,float64(a)))*2
}
写法二:代码
绳子段切分的越多,乘积越大,且3做因数比2更优。
不断剪去 长度3 并用sum累乘
把绳子切为多个长度为 3 的片段,则留下的最后一段绳子的长度可能为 0,1,2 三种情况。
循环结束的三种情况:
n=n-3==2
n长度剩下2,因 n > 4 跳出循环,return 乘积为sum*2。
n=n-3==3
长度刚好可以被剪完,因 n > 4 跳出循环,return 乘积为sum*3。
n=n-3==4
再剪一次的话,长度剩下1,则最后一段绳子长度为 1;
需要把最后的 3 和 1 替换为 2 和 2,因为 2 * 2 > 3 * 1;
因 n > 4 跳出循环,return 乘积 sum*4 即可。
–执行用时:0 ms --内存消耗:1.9 MB
func cuttingRope(n int) int {
if n==1||n==2{
return 1
}
if n==3{
return 2
}
sum:=1
for n>4{
sum*=3
n-=3
}
return sum*n
}