Leetcode 剑指 Offer 14- I/14- II. 剪绳子

Leetcode 剑指 Offer 14- I/14- II. 剪绳子

题目

给你一根长度为 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
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1

示例 2:

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

思路

  • 这道题目本质上就是在问下面的题设的答案:
已知n = k0 + k1 + k2 + ... + k(m - 1), 求k0 * ... * k(m - 1) 的最大值
  • 这种带有限制条件的最值问题可以考虑使用高数之中的构造拉格朗日函数来解决
设F = k0 * k1 * ...k(m - 1) + t(k0 + k1 + ...k(m - 1) - n)
对k0求偏导, -》k1 * k2 * ... k(m - 1) + t = 0
......
对k(m - 1) 求偏导, -》k0 * k1 * ...k(m - 2) + t = 0
对t求偏导, -》k0 + k1 + k2 + ...k(m - 1) = n
容易解得当k0 == k1 == ... k(m - 1)的时候取得最大值
  • 此时得到结论 —— 尽量剪每段一样长就可以达到最大值, 但是剪的段数是不确定的, 所以我们再设每段的长度为x, 在假设可以整除x的前提下, 即
设y = x * x * x ...x (此处x共有n / x个), 此时n可以看成一个固定的常数, 我们只用考虑x的(1/x)的次方
取对数求导可得 —— 当x等于e的时候(即2.7时候)可以取得最大值
  • 但是题目要求分的必须为整数, 所以分别对2和3进行计算
2的(1/2)次方为1.414
3的(1/3)次方为1.442
  • 所以我们每段分成长度为3即可
  • 但是这道题目具有特殊的情况
在一段段剪3的长度之后, 最后剩下长度1, 2
长度为1的情况: 显然将之前的3和这个1分成另外的情况更优:3 * 1 < 2 * 2
长度为2的情况: 显然1 * 1 < 2即不需要再分
发现规律, 在最后剩下的长度小于等于4的时候, 就不用继续剪绳子了,因为该长度就是最大值的组成的部分
  • 由于题目中要求绳子至少要剪成2段, 所以对于初始值n
n = 2: 1 * 1 = 1
n = 3: 1 * 2 = 2

代码

剪绳子I —— golang

func cuttingRope(n int) int {
    if n < 4 {
        return n - 1;
    } else {
        res := 1

        for ;n > 4; {
            res *= 3;
            n -= 3;
        }

        return res * n;
    }
}

剪绳子II —— golang

func cuttingRope(n int) int {
    if n < 4 {
        return n - 1;
    } else {
        res := 1

        for ;n > 4; {
            res = (res * 3) % 1000000007;
            n -= 3;
        }

        return (res * n) % 1000000007;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值