【剑指offer】剪绳子

2024年最全iOS开发 C语言使用笔记 PKCS12 openssl 改 p12密码,C C++面试基础知识 【代码】2024年最全iOS开发 C语言使用笔记 PKCS12 openssl 改 p12密码,C C++面试基础知识。 阅读详情

【题目】给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?

例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

显然,可以尝试着将问题规模减小并挖掘不同规模问题间的关系。

思路一: 将f(n)转变为max(f(n-i)*i)问题,其中i为切分的那段长度为i

根据这个思路,可分别写出对应的递归方法、带备忘的递归方法以及DP方法。

  • 暴力穷举,递归法
class Solution1:
    def cutRope(self, number):
        if number == 2:
            return 1
        if number == 3:
            return 2
        return self.cutRopeCore(number)

    def cutRopeCore(self, number):
        if number <= 3:
            return number

        maxProd = 1    # 初始值,假设全部为1,也可为0
        for i in range(1, number):
            maxProd = max(maxProd, i*self.cutRopeCore(number-i))

        return maxProd

该算法的时间复杂度O(n!) , 空间复杂度O(n)。

  • 带备忘的递归法

显然,在上面的暴力穷举法中有很多重复的子问题计算,因此可以采用缓存机制将这些子问题的结果保存起来方便查询。

class Solution:
    def cutRope(self, number):
        if number == 2:
            return 1
        if number == 3:
            return 2
        cache = [-1] * (number+1)       # index=0为哨兵位
        return self.cutRopeCore(number, cache)

    def cutRopeCore(self, number, cache):
        if number <= 3:
            cache[number] = number
            return cache[number]

        for i in range(1, number+1):
            if cache[i] == -1:
                cache[i] = self.cutRopeCore(i, cache)
            cache[number] = max(cache[number], cache[i] * (number-i))

        return cache[number]

该算法的时间复杂度O(n^2),空间复杂度O(n)。

  • DP算法

参照上面的递归算法,我们从底向上就可以提出对应的DP算法,其中的状态变量为各子问题的最优解。

class Solution:
    def cutRope(self, number):
        if number == 2:
            return 1
        if number == 3:
            return 2

        # dps: 各长度的最优子长度乘积
        dps = [-1] * (number+1)       # index=0为哨兵位
        for i in range(1, number+1):
            if i <= 3:
                dps[i] = i
            else:
                for j in range(1, i):
                    dps[i] = max(dps[i], j*dps[i-j])

        return dps[-1]  return cache[number]

该算法的时间复杂度O(n^2),空间复杂度O(n)

思路二:将f(n)转变为max(f(n-i)*f(i)),即两个最优子问题的乘积

在思路一中我们将子问题的规模不断-1,另一方面我们参考归并排序的想法,将子问题拆分为两个子问题的乘机。同样可以分别给出对应的归方法、带备忘的递归方法以及DP方法。

采用这种思路还有一个技巧,因为拆分子问题的对称性,所以在算法中只要考虑一般的搜索空间即可。

  • 递归算法
class Solution:
    def cutRope(self, number):
        if number == 2:
            return 1
        if number == 3:
            return 2
        return self.cutRopeCore(number)

    def cutRopeCore(self, number):
        if number <= 3:
            return number

        maxProd = 1    # 初始值,假设全部为1,也可为0
        for i in range(1, number//2+1):       # 注意折半
            maxProd = max(maxProd, self.cutRopeCore(i)*self.cutRopeCore(number-i))

        return maxProd
  • 带备忘的递归算法
class Solution2:
    def cutRope(self, number):
        if number == 2:
            return 1
        if number == 3:
            return 2
        cache = [-1] * (number+1)    # index=0为哨兵位
        return self.cutRopeCore(number, cache)

    def cutRopeCore(self, number, cache):
        if number <= 3:
            cache[number] = number
            return cache[number]

        for i in range(1, number//2+1):       # 注意折半, 注意+1
            if cache[i] == -1:
                cache[i] = self.cutRopeCore(i, cache)
            if cache[number-i] == -1:
                cache[number-1] = self.cutRopeCore(number-i, cache)
            cache[number] = max(cache[number], cache[i]*cache[number-i])

        return cache[number]
  • DP算法
class Solution:
    def cutRope(self, number):
        if number == 2:
            return 1
        if number == 3:
            return 2

        dps = [-1] * (number+1)    # index=0为哨兵位
        for i in range(1, number+1):
            if i <= 3:
                dps[i] = i
            else:
                for j in range(1, i//2+1):
                    dps[i] = max(dps[i], dps[j]*dps[i-j])

        return dps[-1]
思路三:寻找f(n-1)和f(n)的直接关系

上面的两种思路都搜索了1~(n-1)规模的子问题,那么能否直接找到f(n-1)和f(n)间的关系呢?

假设我们现在对于f(n-1)已经有了最优的切分方案,那么当问题规模变为n时,我们该如何演变呢?此时,有三种选择:
(1)新增的1为新的一段,显然这种方案对于面积增加没有任何增益,因此舍弃;
(2)添加到一段上,显然添加到最短的一段对面积的增益越大;
(3)添加到一段并做重新拆分,此时又有了两个新问题:a) 添加到哪一段;b) 该段如何重新分割。这里不给证明的给出如下答案:选择最长的子段,分割为两段,且两段的距离尽可能相近。

由此可以给出对应的代码:

import math
class Solution:
    def cutRope(self, number):
        # write code here
        split_list = [1]
        for i in range(2, number + 1):
            minVal = min(split_list)
            maxVal = max(split_list)
            ratio_add_minVal = (minVal + 1) / minVal

            split_after_maxVal = int(math.sqrt(maxVal + 1))
            ratio_split_maxVal = (maxVal + 1 - split_after_maxVal) * split_after_maxVal / maxVal

            if ratio_split_maxVal >= ratio_add_minVal:
                split_list.remove(maxVal)
                split_list.extend([split_after_maxVal, maxVal + 1 - split_after_maxVal])

            else:
                split_list.remove(minVal)
                split_list.append(minVal + 1)

        prod = 1
        for i in split_list:
            prod *= i

        return prod

上述方案可以给出最优方案的各子段的情况,如
n=8, 对应的子段方案为[3, 2, 3]
n=15, 对应的子段方案为[3, 3, 3, 2, 2]
似乎各子段都是2和3的组合。

我们不妨从1开始,手动给出不限条件下各长度的最优解,确认里面的规律:
n=1, 不做分割 [1]
n=2, 不做分割 [2]
n=3, 不做分割 [3]
n=4, 分割为 [2, 2]
n=6, 分割为[2, 3]
n=7, 分割为 [2, 2, 3]
n = 8, 分割为 [2, 3, 3]
n = 9,分割为 [3, 3, 3]
…

不难看出,最优方案倾向于尽量分割为3的子段,但当最后一段为1时,需要和3重新组合起来(变成4)将其拆分为两个2。因此,我们可以给出下面的解决思路。

思路四:从数学上寻找关系
import math

class Solution:
    def cutRope(self, number):
        # write code here
        if number == 2:
            return 1
        if number == 3:
            return 2

        timesOf3 = number//3
        if number % 3 == 1:
            timesOf3 -= 1            # 若余数为1,与一个3凑成2*2

        timesOf2 = (number - timesOf3 * 3)//2

        return math.pow(3, timesOf3) * math.pow(2, timesOf2)

问题虽然解决了,为什么最优方案倾向于分裂为3的子段呢?根据Jesen不等式,将n分为k段,其乘积最大值当且仅当各段相等,且值为n/k时,此时乘积为(n/k)^k,可以给出不同k时的函数曲线如下:
在这里插入图片描述
不难看到无论n为多少,其峰值均在3附近。

总结

1)如何将问题拆解为子问题,并建立联系是采用递归或DP类算法的核心。常见的包括-1规模,1~n-1规模,对半规模等。
2)注意边界条件和递归终止条件。
3)注意约束条件,如本题要求绳子必须切割,所以n=2、3时必须单独处理。但是在递归的子问题最优化中又需要考虑他们的最优解。这也是本题的一个坑。

《剑指offer》面试题14:剪绳子问题 --- 看完就懂了 这一类的问题,有2种不同的方式来解决, 一个是动态规划, 还有一个是贪婪算法。具体的教程网上有很多, 这里主要是从数学的角度对贪婪算法做一个补充说明。 话不多说,题目先甩为敬意! 题目: 给你一根长度为n的绳子,请把绳子剪成m段 (m和n都是整数,n&amp;amp;amp;amp;amp;amp;amp;gt;1并且m&amp;amp;amp;amp;amp;amp;amp;gt;1)每段绳子的长度记为k[0],k[1],…,k[m].请问k[0]k[1]…*k[m]可能的最大乘积是多少? 阅读详情

相关推荐

剑指offer--剪绳子

剑指offer–剪绳子 文章目录剑指offer--剪绳子一、题目描述二、分析三、代码 一、题目描述 二、分析 既然这道题考的是贪心,我们就用贪心来解决,不用其他的方法; 动态规划求解问题的四个特征: ①求一个问题的最优解; ②整体的问题的最优解是依赖于各个子问题的最优解; ③小问题之间还有相互重叠的更小的子问题; ④从上往下分析问题,从下往上求解问题; 对于这道题,我们先确定最多可以分得的段数,对于长度为n的绳子(n > 1),如何把它分为整数长的m段(m > 1), 对于m,我们最大可

wolfGuiDao的博客 753

【剑指Offer】剪绳子问题——四种解法

剪绳子问题——四种解法题目描述:输入描述:返回值描述:示例1:解题思路:方法1:暴力递归方法2:记忆化递归方法三:动态规划方法四,数学原理 题目描述: 给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。 输入描述: 输入一个数n(2<=n<=60) 返回

小哲的博客 4775

农经权二轮延包—地块示意图生成

本文介绍了地块示意图制作软件的使用方法及模板制作要点。软件通过设置六个参数(示意图模板、属性数据、地块DBF、导航图、地块图片及存放位置)自动生成Word文档,并可导出PDF。文章详细说明了5页Word模板的制作过程,包括页脚三栏设置和页码插入技巧,支持每户最多28个地块的情况。同时指出该软件生成的图片分辨率(300dpi)满足清晰度要求,并提及软件免费提供插件但收费提供后续服务。

weixin_47364423的博客 1114

剑指offer面试题14-I:剪绳子

思路一:贪心算法 推论一: 将绳子 以相等的长度等分为多段 ,得到的乘积最大。 推论二: 尽可能将绳子以长度 33 等分为多段时,乘积最大。 核心思路是:尽可能把绳子分成长度为3的小段,这样乘积最大。 步骤如下: (1)如果 n === 4,返回4 (2)如果 n > 4,分成尽可能多的长度为3的小段,每次循环长度n减去3,乘积res乘以3;最后返 回时乘以小于等于4的最后一小段 class Solution { public: int cuttingRop...

weixin_39035802的博客 782

CCS20实战入门:第一个工程搭建示例

通过实际操作演示如何在ccs20中创建并配置首个开发项目,涵盖环境设置与基础调试步骤,帮助新手快速上手ccs20集成开发环境,提升嵌入式开发效率。

weixin_31185473的博客 884

PSINS惯性系初始对准与代码解读

本文参考“摇摆基座上基于信息的捷联惯导粗对准研究”(秦永元),以及“严恭敏博士后研究报告”,详细解读并推导了静基座惯性系对准算法,并与PSINS代码进行对照解读。

u011012050的博客 6753

剑指offer刷题笔记—剪绳子

剑指offer刷题笔记—剪绳子

m0_48683294的博客 282

用ST25DV芯片+KiCad快速设计NFC标签天线:参数计算/脚本生成/实测优化全流程

本文详细介绍了使用ST25DV芯片和KiCad工具设计NFC标签天线的全流程,包括参数计算、脚本生成和实测优化。通过解析芯片等效工作原理和设计思路,帮助开发者避开常见陷阱,实现高效、可量产的天线设计。文章还提供了Python计算工具和KiCad自动化脚本,大幅提升设计效率和成功率。

jj890的博客 758

【力扣】第 24 天 数学(中等)

剑指 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。 题解 尽可能将绳子以长度 3 等分为多段时,乘积最大。 当 n≤3n \leq 3n≤3时,按照规则应不切分,但由于题目要求必须剪成 m>1 段

毛毛的博客 3956

金蝶个版本下载地址,记得保存收藏。

专业版 V10.0 http://downloads.cmcloud.cn/kis/kis_pro/10.0/kiszybV10sp1.rar V11.0 http://downloads.cmcloud.cn/kis/kis_pro/11.0/KISV11Setup.rar V12.0 http://dow...

饺子的博客 2505

小工匠聊架构-分布式场景下的并发幂等性常见的解决方案

Pre 我们来回顾下单体时代 单体时代,应用部署在一台主机上,可以使用JVM级别的锁来控制并发请求 。 随着应用规模的不断扩大,集群化或者微服务化的分布式部署越来越普及,每个应用都是一个单独的JVM应用,所以单体时代的这种处理方式已经无法满足当前架构下的业务需求了。 JVM级别的锁已经无法满足跨进程之间访问控制了,进而演化出来了分布式锁。 分布式锁 能否解决幂等性问题? 分布式锁解决什么问题? 简言之: 解决跨进程间无法共享本地资源的问题 ,解决的是分布式场景下并发访问的问题。 为什么需要确保并发.

小工匠 2万+

剑指Offer: 剪绳子

剑指Offer: 剪绳子 题目描述 给你一根长度为 n 绳子,请把绳子剪成 m 段(m、n 都是整数,2 ≤ n ≤ 58 并且 m ≥ 2) 每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]k[1] … k[m] 可能的最大乘积是多少? 例如当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到最大的乘积18 样例 输入:8 输出:18 算法 贪心 N = m...

Erice_s的博客 441

实战:RK3568 Android14 调试 ES8388 音频驱动 (MIC 篇)

这个板子的MIC设计使用了硬件自动切换方案,极大简化了软件层面的逻辑。我们不需要根据耳机插拔事件去编写复杂的路由切换代码,只需要守住 LIN1/RIN1 这一个入口,配置好增益,剩下的交给那颗 SGM3157 芯片即可。祝您的录音功能调试顺利!

qq_33427070的博客 1678

剑指Offer 14——剪绳子

文章目录1. 剑指Offer 14- I 剪绳子1.1 递归1.2 动态规划1.3 贪心2. 剑指Offer 14.II ——剪绳子 1. 剑指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: 输

weixin_43691723的博客 255

Qt应用软件【协议篇】自定义协议处理串口半包贴包

Qt串口数据,半包,贴包,丢包数据处理

小鱼酱的博客 1211

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

剑指offer 剪绳子JZ67

剑指offer 剪绳子目录题目描述题目理解暴力递归无记忆有记忆递归动态规划 目录 本文是参考牛客网的官方题解结合自己理解写的,官方题解:牛客官方题解 题目描述 给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。 输入描述: 输入一个数n,意义见题面。(2 <=

weixin_43568893的博客 288

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

剑指offer——剪绳子

剑指offer——剪绳子 【题目描述】 给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。 输入描述: 输入一个数n,意义见题面。(2 <= n...

ma_ke_xin的博客 240

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

剑指Offer:剪绳子

剑指Offer:剪绳子 题目描述:给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少? 解题步骤: 1、 状态定义:dp[i]表示剪断长度为i的绳子所得到的最大乘积 2、 状态转移方程:dp[i]=max(dp[i],dp[i-j]*j) ...

张毅的博客 434

剑指Offer-剪绳子(一)

剑指Offer-剪绳子(一) 给你一根长度为 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...

Galip的博客 184

【剑指offer14-I】【C++】剪绳子【动态规划】

【剑指offer14-I】【C++】剪绳子题目题解 题目 给你一根长度为 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 输出:

程序员阿浪 413

剑指 Offer 14- I. 剪绳子

剑指 Offer 14- I. 剪绳子 链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/ 用算法几何不等式,m个数字和是一定的情况下,要想使得乘积是最大的,这m个数字肯定是相等的,然后考虑相等的时候利用求导得出最小值(https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/mian-shi-ti-14-i-jian-sheng-zi-tan-xin-si-xiang-.

breeze_blows的博客 222

剑指Offer14- I:剪绳子java实现

剑指 Offer 14- I. 剪绳子 https://leetcode-cn.com/problems/jian-sheng-zi-lcof/ 给你一根长度为 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 输

WukongGo的博客 369

剑指Offer刷题(剪绳子)

剑指Offer刷题(剪绳子)一.题目描述二.代码(C++)三.提交记录四.备注 一.题目描述 给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。 输入描述: 输入一个数n,意义见题面。(2 <= n <= 60) 输出描述: 输出答案。 示例1

Umbraner的博客 270

剑指offer-贪心-剪绳子

剑指offer 题目:剪绳子 描述:给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。 代码: #include <iostream> using namespace std; class Solution{ public: int cutR

年糕的博客 189

leetcode 剑指offer 14-II.剪绳子 II

原题如下 https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/ 与 343.整数拆分 相同 https://leetcode-cn.com/problems/integer-break/ 题解 方法一 总体思路就是,尽量拆成若干个3,倘若拆不出整个3,则尽量出现2,余1的不要拆成1和3,而要拆成2和2. //2020.06.09 重做343 //执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户 //内存消耗 :36.2 M

zhuruihe2014的博客 334

Java详解剑指offer面试题14--剪绳子

Java详解剑指offer面试题14–剪绳子 给你一根长度为n的绳子,把绳子剪成m段(m、n都是整数且m > 1, n > 1),m段绳子的长度依然是整数,求m段绳子的长度乘积最大为多少?比如绳子长度为8,我们可以分成2段、3段、4段...8段,只有分成3段且长度分别是2、3、3时能得到最大乘积18 动态规划版本 要求大问题的最优解,可以将大问题分解成小问题,分解的小问题也有最优解,因此将小问题的最优解组合起来就能得到大问题的最优解。若将f(n)定义为将长度为n的绳子分成若干段后的各段长度

快乐李同学的博客 511
上一篇: 【最优二叉树】Huffman树
下一篇: 【文本分类】常见文本分类深度学习模型汇总
guofei_fly
博客等级 码龄8年 204粉丝 162原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值