剑指 Offer 14- I. 剪绳子 [中等]

剑指 Offer 14- I. 剪绳子 [中等]

题目描述

给你一根长度为 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。

示例:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36

限制:

2 <= n <= 58

解题思路:

贪心思路:

设一绳子长度为 n ( n>1 ),则其必可被切分为两段 n=n_1+n_2
根据经验推测,切分的两数字乘积往往原数字更大,即往往有 n_1 × n_2 > n_1 + n_2 = n

例如绳子长度为 6 : 6 = 3 + 3 < 3 × 3 = 9
也有少数反例,例如 2 : 2 = 1 + 1 > 1 × 1 = 1

推论一:

合理的切分方案可以带来更大的乘积。

设一绳子长度为 n (n>1 ),切分为两段 n=n_1+n_2,切分为三段 n=n_1+n_2+n_3
根据经验推测,三段 的乘积往往更大,即往往有 n_1 × n_2 × n_3 > n_1 × n_2

  • 例如绳子长度为 9 : 两段 9=4+5 和 三段 9=3+3+3,则有4×5<3×3×3
  • 也有少数反例,例如 6 : 两段 6=3+3 和 三段 6=2+2+2,则有 3×3>2×2×2

推论二:

若切分方案合理,绳子段切分的越多,乘积越大。
总体上看,貌似长绳子切分为越多段乘积越大,但其实到某个长度分界点后,乘积到达最大值,就不应再切分了。
问题转化: 是否有优先级最高的长度 x 存在?若有,则应该尽可能把绳子以 x 长度切为多段,以获取最大乘积。

推论三:

为使乘积最大,只有长度为 2 和 3 的绳子不应再切分,且 3 比 2 更优 (详情见下表) 。

绳子切分方案乘积结论
2=1+11×1=12 不应切分
3=1+21×2=23 不应切分
4=2+2=1+32×2=4>1×3=34 和 2 等价,且2+2 比 1+3 更优
5=2+3=1+42×3=6>1×4=45 应切分为 2+3
6=3+3=2+2+23×3=9>2×2×2=86 应切分为3+3 ,进而推出 3 比 2 更优
>7长绳(长度>7)可转化为多个短绳(长度1~6),因此肯定应切分

结论:尽可能把绳子分成长度为3的小段,这样乘积最大

复杂度分析:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

代码:

package main

import "fmt"

func cuttingRope(n int) int {
	if n < 4 {
		return n-1
	}
	res :=1
	for n>4 {
		res *=3
		n -= 3
	}
	return res * n // 乘以剩余的数
}

func main(){
	fmt.Println(cuttingRope(1))
	fmt.Println(cuttingRope(2))
	fmt.Println(cuttingRope(3))
	fmt.Println(cuttingRope(4))
	fmt.Println(cuttingRope(5))
	fmt.Println(cuttingRope(6))
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值