zoukankan      html  css  js  c++  java
  • 剑指 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。

    示例 1:

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

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

    2 <= n <= 58

    • 解法一:数学归纳法

    分析:

    假设长度为n的绳子切成a段:n=n1+n2+...+na

    求解的目标是:max(n1×n2×...×na)

    首先回顾下算术几何均值不等式:当且仅当 

    n_1 = n_2 = ... = nn1=n2=...=na 时等号成立

    然后这里就需要大量的数学推导了.....

    将绳子按照x长度分成a段的话,n=ax,则乘积为x^a,此时

    x^a = x^(n/x) = (x^(1/x))^n

    由于n为常数,因此 x^(1/x)为最大值时,长度的乘积最大。

    接着,可以将这个问题转化为求y = x^(1/x)的极大值问题,此时可以对x求导:

     另导数为0, 此时有1-lnx=0,当且仅当x=e时有极大值点。

    再来,可以很容易推导出,只有将绳子等分尽量多3的长度段有最大值,但是当分成长度为3还有余数时,此时有2种情况:

    余一段为2,此时则直接保留为2的长度

    余一段为1,此时要考虑把拿一段长度为3的和长度为1的一起拼成两段长度为2的,此时才是最大。

    时间复杂度O(1)。

    class Solution:
        '''
        用数学归纳法求解
        '''
        def cuttingRope(self, n: int) -> int:
            max_long = 0
            if n < 3:
                return 1
            if n == 3:
                return 2
            if n % 3 == 0:
                max_long = 3 ** (n//3)
            elif n % 3 == 2:
                max_long = 2 * (3 ** (n//3))
            else:
                max_long = 2 * 2 * (3 ** ((n//3) - 1))
            return max_long
    
    • 解法二:动态规划

    设 F(n)F(n) 为长度为 nn 的绳子可以得到的最大乘积,对于每一个 F(n)

    F(n),可以得到如下分解:

     此时可以把求解 

    F(n)F(n) 的问题分解成求解 F(n-1)F(n1) 的问题

    直到求解到 F(2)F(2) 时,F(2) = 1F(2)=1,递推回去,问题就得到了解决。

    这里针对这种分治的思想,需要注意:我们每次将一段绳子剪成两段时,剩下的部分可以继续剪,也可以不剪。

    当将一段长度为i的绳子从j出剪下时,此时有3种情况:

    1)维持原状态

    2)剪下来的部分为i-j,然后就不再剪了

    3)剪下来的部分是i-j,然后对i-j继续剪。

    此时建立一维数组dp

    • 边界条件:dp[1] = dp[2] = 1,表示长度为 2 的绳子最大乘积为 1;
    • 状态转移方程:dp[i] = max(dp[i], max((i - j) * j, j * dp[i - j])),可以这样理解:

    代码:

    class Solution:
        '''
        动态规划解法
        '''
        def cuttingRope(self, n: int) -> int:
            dp = [0 for i in range(n+1)] 
            dp[2] = 1 
            for i in range(3, n+1):
                for j in range(i):
                    dp[i] = max(dp[i], max(j*(i - j), j * dp[i-j]))
            return dp[n]

    时间复杂度O(n2),空间复杂度O(n).

     参考题解:

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

    https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/xiang-jie-bao-li-di-gui-ji-yi-hua-ji-zhu-dong-tai-/

    本博客仅用于个人学习。

    n 1​ +n 2​ +...+n a​ ​ ≥ a  n 1​ n 2​ ...n a​ ​ 
    推论一: 将绳子 以相等的长度等分为多段 ,得到的乘积最大。
    作者:jyd链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/mian-shi-ti-14-i-jian-sheng-zi-tan-xin-si-xiang-by/来源:力扣(LeetCode)著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    jmeter的beanshell脚本编写
    基于 Flask 的简易 Mock 平台
    mock-server
    linux环境jmeter- java环境安装配置
    服务器监控环境搭建 telegraf+influxdb+grafana框架
    聚类算法:凝聚层次聚类
    python中cursor操作数据库
    python中if __name__ == '__main__': 的解析
    python连接mysql数据库
    Python3.5,flask在命令行执行 [python] view plain copy import pymysql 连接mysql数据库MySQLdb
  • 原文地址:https://www.cnblogs.com/yeshengCqupt/p/13417080.html
Copyright © 2011-2022 走看看