• 14- I. 剪绳子


    题目:给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m] 。请问 k[0]*k[1]*...*k[m] 可能的最大乘积是多少?例如,当绳子的长度是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的绳子最大乘积的基础上,长度n+1绳子的最大乘积可能来源依赖于前面已知求解。
    定义辅助数据结构:记长度为n的绳子最大乘积为s[n],简单起见,不考虑索引偏移问题,初始化s = [1]*(n+1)。
    假设当前处理长度为i的绳子最大乘积问题:

    (1)从i中截取一块长度为j的绳子,剩余长度i-j的最大乘积为s[i-j],即最后一段长度为j的方案带来的乘积为j*s[i-j];
    (2)对j从1到n-1进行遍历,取最大值;
    (3)由于我们假定长度i-j绳子最大乘积为s[i-j]的前提是要求i-j必须进行分割(m>1),然而对于从i中截取j这一事件本身已经满足分割要求,所以上述取最值还需增加一个补丁:即仅对长度i进行i-j和j两段分割的判断。

    class Solution:
        def cuttingRope(self, n: int) -> int:
            s = [1]*(n+1)
            for i in range(2, n+1):
                for j in range(1, i):
                    s[i] = max(s[i], s[j]*(i-j), j*(i-j))
            return s[n]

    方法二:数学公式推导

    推论:尽可能将绳子以长度3等分为多段时,乘积最大!

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

    class Solution:
        def cuttingRope(self, n: int) -> int:
            if n <= 3: return n - 1
            a, b = n // 3, n % 3
            if b == 0: return int(math.pow(3, a))  #留下的最后一段绳子的长度为 0
            if b == 1: return int(math.pow(3, a - 1) * 4)  #留下的最后一段绳子的长度为 1
    return int(math.pow(3, a) * 2)
  • 相关阅读:
    优化C/C++代码的小技巧
    闭包,看这一篇就够了——带你看透闭包的本质,百发百中
    7215:简单的整数划分问题
    常见问题最佳实践三:服务启动顺序
    JAVA 用分苹果来理解本题
    arcgis访问格式
    墨卡托投影
    C# 从DataTable中取值
    Base64编码的字符串与图片的转换 C#
    墨卡托投影实现
  • 原文地址:https://www.cnblogs.com/USTC-ZCC/p/12630865.html
Copyright © 2020-2023  润新知