题目描述

给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

(2 <= n <= 60)

剪绳子-剑指offer-python_段长度

解题:
4 : 22
5 : 2
3
6 : 33
7 : 2
23 或者43
8 : 233
9 : 333
10:2233 或者433
11:2
333
12:3333
13:2
2333 或者4333

由此可见,要想满足 k[1]+…+k[m]=n 且 k[1]✖…✖ k[m]最大,k[0]~k[m]只能是2或者3。有4的情况理解成22即可。大于4的比如5和6,那就是再拆分5<23,6<33。要满足上面的两个条件2的数量肯定比3的数量少,因为222 < 33。
所以直接用n除以3取余看是否是3的倍数即余数为0,是的话就说明没有2,如果是1的话就说明有2个2,因为3+1=4=2*2嘛,如果是其它数值的说明只有一个2。
另外有两种特殊情况: n=2和n=3,n=2则是1+1即只能是1+1,n=3只能是2+1。

-*- coding:utf-8 -*-
class Solution:
def cutRope(self, number):
if number ==2:
return 1
if number ==3:
return 2
i = number / 3
j = number % 3
if j == 0:
return int(3**i)
elif j==1:
return 2*2*int(3**(i-1))
else:
return 2*int(3**i)
# write code here

此题使用DP算法的解法:

先自上而下分析,在长度为n的绳子所求为f(n),剪下一刀后剩下的两段长度是i和n-i,在这个上面还可能继续减(子问题),所以状态转移方程:

剪绳子-剑指offer-python_状态转移_02


然后自下而上的解决问题,可以从f(1)开始向上计算并保存,最终获得f(n)的值。

由于当i大于n//2时,就不用在计算了,因为是重复的,重复计算因此实际上:

剪绳子-剑指offer-python_段长度_03