剑指 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)著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

原文地址:https://www.cnblogs.com/yeshengCqupt/p/13417080.html