Q67 剪绳子

题目描述

给你一根长度为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 <= 60)
输出描述:
输出答案。

示例1
输入
8
输出
18

链接:https://www.nowcoder.com/questionTerminal/57d85990ba5b440ab888fc72b0751bf8?answerType=1&f=discussion
来源:牛客网

递归

我们先定义函数f(n)为把绳子剪成若干段之后的各段长度乘积的最大值.在剪第一刀的时候,我们会有n-1种可能的选择,也就是说剪出来的第一段绳子的长度可能为1,2,…n-1.因此就有了递归公式 f(n) = max(f(i)*f(n-i)),其中0<i<n.

class Solution:
    def cutRope(self, number):
        # write code here
        if number<2:
            return 0
        if number==2:
            return 1
        if number==3:
            return 2
        return self.cut(number)
    def cut(self,number):
        if number<5:
            return number
        maxi = 0
        for i in range(1,number/2+1):
            maxi = max(self.cut(i)*self.cut(number-i),maxi)
        return maxi

链接:https://www.nowcoder.com/questionTerminal/57d85990ba5b440ab888fc72b0751bf8?answerType=1&f=discussion
来源:牛客网

动态规划

首先定义函数f(n)为把长度为n的绳子剪成若干段后各段长度乘积的最大值。在剪第一刀的时候,我们有n-1种可能的选择,也就是剪出来的第一段绳子的可能长度为1,2,…n-1。因此f(n)=max(f(i)xf(n-i)),其中0<i<n.
  这是一个从上至下的递归公式。由于递归会有很多重复的子问题,从而有大量不必要的重复计算。一个更好的办法是按照从下而上的顺序计算,也就是说我们先得到f(2)、f(3),再得到f(4)、f(5),直到得到f(n)。
  当绳子的长度为2时,只可能剪成长度为1的两段,因此f(2)等于1.当绳子的长度为3时,可能把绳子剪成长度为1和2的两段或者长度都为1的三段,由于1x2>1x1x1,因此f(3)=2

也就是先计算f(1)、f(2)、f(3)…的值,大的值等于小的值的乘积

在代码中,子问题的最优解存储在数组array里。数组中第i个元素表示把长度为i的绳子剪成若干段之后各段长度乘积的最大值,即f(i)。我们注意到代码中的第一个for循环变量i是顺序递增的,这意味着计算顺序是自下而上的。因此,在求f(i)之前,对于每一个j(0<i<j)而言,f(j)都已经求解出来了,并且结果保存在array[j]里,为了求解f(i),我们需要求出所有可能的f(j)xf(i-j)并比较得出它们的最大值。这就是代码中第二个for循环的功能。

# -*- coding:utf-8 -*-
class Solution:
    def cutRope(self, number):
        # write code here
        if number<2:
            return 0
        if number==2:
            return 1
        if number==3:
            return 2
        array = [0]*(number+1)
        array[0] = 0
        array[1] = 1
        array[2] = 2
        array[3] = 3
        for i in range(4,number+1):
            maxi = 0
            for j in range(1,i/2+1):
                maxi = max(array[j]*array[i-j],maxi)
            array[i] = maxi
        return array[number] 

数学

绳子长度为n,分成m分,那先设每分长度为x, 分数m=n/x 那么结果就是 n/x个 x 相乘 f(x)=x^(n/x) 求导:如下图
在这里插入图片描述
链接:https://www.nowcoder.com/questionTerminal/57d85990ba5b440ab888fc72b0751bf8?answerType=1&f=discussion
来源:牛客网

所以问题就回到了n/3的个数上面
当n能被3整除的时候,乘积=n^(n/3)
当n除3余1的时候,这时候发现多了一个1,这个1是不是很鸡肋,但是把前面的一个3拿出来,把这个一个1和前面一个3 分解为2和2,就变大了,所以乘积为 3^(n/3 - 1) * 4
当n除3余2的时候,乘积为n^(n/3) * 2

# -*- coding:utf-8 -*-
class Solution:
    def cutRope(self, number):
        # write code here
        if number<2:
            return 0
        if number==2:
            return 1
        if number==3:
            return 2
        tmp = number%3
        result = 0
        if tmp==0:
            result = pow(3,number/3)
        if tmp==1:
            result = pow(3,number/3-1)*4
        if tmp==2:
            result = pow(3,number/3)*2
        return result 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值