Leetcode刷题笔记——剑指 Offer 14- I. 剪绳子(中等)


题目描述

给你一根长度为 n n n 的绳子,请把绳子剪成整数长度的 m m m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k [ 0 ] , k [ 1 ] . . . k [ m − 1 ] k[0],k[1]...k[m-1] k[0],k[1]...k[m1] 。请问 k [ 0 ] ∗ k [ 1 ] ∗ . . . ∗ k [ m − 1 ] k[0]*k[1]*...*k[m-1] k[0]k[1]...k[m1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

解法

设将长度为 n 的绳子切为 a 段:
n = n 1 + n 2 + . . . + n a n=n_1+n_2+...+n_a n=n1+n2+...+na
本题等价于求解:
m a x ( n 1 × n 2 × . . . × n a ) max(n_1\times n_2\times ... \times n_a) max(n1×n2×...×na)
数学推导:
以下公式为“算术几何均值不等式” ,等号当且仅当 n 1 = n 2 = . . . = n a n_1 = n_2 = ... = n_a n1=n2=...=na 时成立。
n = n 1 + n 2 + . . . + n a a ≥ n 1 n 2 . . . n a a \frac{n=n_1+n_2+...+n_a}{a}\geq \sqrt[a]{n_1n_2...n_a} an=n1+n2+...+naan1n2...na
(略)

推论一: 将绳子 以相等的长度等分为多段 ,得到的乘积最大。
推论二: 尽可能将绳子以长度 3 3 3 等分为多段时,乘积最大。

切分规则:

  1. 最优: 3 3 3 。把绳子尽可能切为多个长度为 3 3 3 的片段,留下的最后一段绳子的长度可能为 0 , 1 , 2 0,1,2 0,1,2 三种情况。
  2. 次优: 2 2 2 。若最后一段绳子长度为 2 2 2 ;则保留,不再拆为 1 + 1 1+1 1+1
  3. 最差: 1 1 1 。若最后一段绳子长度为 1 1 1 ;则应把一份 3 + 1 3 + 1 3+1 替换为 2 + 2 2 + 2 2+2,因为 2 × 2 > 3 × 1 2 \times 2 > 3 \times 1 2×2>3×1

算法流程:

  1. n ≤ 3 n \leq 3 n3 时,按照规则应不切分,但由于题目要求必须剪成 m > 1 m>1 m>1 段,因此必须剪出一段长度为 1 1 1 的绳子,即返回 n − 1 n - 1 n1
  2. n > 3 n>3 n>3 时,求 n n n 除以 3 3 3 的 整数部分 a a a 和 余数部分 b b b (即 n = 3 a + b n = 3a + b n=3a+b),并分为以下三种情况:
    • b = 0 b = 0 b=0 时,直接返回 3 a 3^a 3a
    • b = 1 b = 1 b=1 时,要将一个 1 + 3 1 + 3 1+3 转换为 2 + 2 2+2 2+2,因此返回 3 a − 1 × 4 3^{a-1} \times 4 3a1×4
    • b = 2 b = 2 b=2 时,返回 3 a × 2 3^a \times 2 3a×2

复杂度分析

时间复杂度 O ( 1 ) O(1) O(1) : 仅有求整、求余、次方运算。

  • 求整和求余运算:资料提到不超过机器数的整数可以看作是 O ( 1 ) O(1) O(1)
  • 幂运算:查阅资料,提到浮点取幂为 O ( 1 ) O(1) O(1)

空间复杂度 O ( 1 ) O(1) O(1) : 变量 a a a b b b 使用常数大小额外空间。

C++代码实现

class Solution {
public:
    int cuttingRope(int n) {
        if(n <= 3) return n - 1;
        int a = n / 3, b = n % 3;
        if(b == 0) return (int)pow(3, a);
        if(b == 1) return (int)pow(3, a - 1) * 4;
        return (int)pow(3, a) * 2;
    }
};

贪心解法

力扣大佬说适合于时间有限情况下快速解题
思路:
设一绳子长度为 n n n ( n > 1 ) ( n>1) (n>1),则其必可被切分为两段 n = n 1 + n 2 n=n_1+n_2 n=n1+n2
根据经验推测,切分的两数字乘积往往比原数字更大,即往往有 n 1 × n 2 > n 1 + n 2 = n n_1 \times n_2 > n_1 + n_2 = n n1×n2>n1+n2=n

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

推论一: 合理的切分方案可以带来更大的乘积。
设一绳子长度为 n ( n > 1 ) n ( n>1 ) n(n>1),切分为两段 n = n 1 + n 2 n=n_1+n_2 n=n1+n2 ,切分为三段 n = n 1 + n 2 + n 3 n=n_1+n_2+n_3 n=n1+n2+n3
根据经验推测,三段 的乘积往往更大,即往往有 n 1 n 2 n 3 > n 1 n 2 n_1 n_2 n_3 > n_1 n_2 n1n2n3>n1n2

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

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

推论三: 为使乘积最大,只有长度为 2 2 2 3 3 3 的绳子不应再切分,且 3 3 3 2 2 2 更优 (详情见下表)。
在这里插入图片描述

参考链接

[1] https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/mian-shi-ti-14-i-jian-sheng-zi-tan-xin-si-xiang-by/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卑微小岳在线debug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值