給你一根長度爲 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
思路1 查表法
如下
class Solution:
def cuttingRope(self, n: int) -> int:
res = [0, 0, 1, 2, 4, 6, 9, 12, 18, 27, 36, 54, 81, 108, 162, 243, 324, 486, 729, 972, 1458, 2187, 2916, 4374, 6561, 8748,13122, 19683, 26244, 39366, 59049, 78732, 118098, 177147, 236196, 354294, 531441, 708588, 1062882, 1594323, 2125764,3188646, 4782969, 6377292, 9565938, 14348907, 19131876, 28697814, 43046721, 57395628, 86093442, 129140163, 172186884,258280326, 387420489, 516560652, 774840978, 1162261467, 1549681956]
return res[n]
思路2 利用數學知識求解
分繩子時每段長度應儘可能爲3,若實在無法爲3,可爲2。(若長度實在太短無法爲2則可爲1.)
直觀上也可以理解:
假設最優乘積n1*n2*n3...*na中存在ni=4,則可以將ni拆爲(2,2),積不變。這意味着3和2可以完全替代4,且2比1優先。
同理,假設最優乘積n1*n2*n3...*na中存在ni=5,則可以將ni拆爲(2,3),積2*3=6>5.與n1*n2*n3...*na是最優乘積矛盾。因此,最優乘積中的長度必不可能爲5.
再同理,假設最優乘積n1*n2*n3...*na中存在ni=6,則可以將ni拆爲(3,3),積3*3=9>6.與n1*n2*n3...*na是最優乘積矛盾。因此,最優乘積中的長度必不可能爲6.
以此類推,不難理解:分繩子時每段長度應儘可能爲3,若實在無法爲3,可爲2。(若長度實在太短無法爲2則可爲1.)
這樣,我們就可以有如下代碼:
class Solution:
def cuttingRope(self, n: int) -> int:
if n <= 3: # n>1且m>1. 若n=2,則返回1;若n=3則返回2
return n -1
mod_type = n % 3 # n>=4。餘數只能是0,1,2
power3 = n // 3
power2 = 0
if mod_type == 1: # 如果餘數爲1.則必然能夠和一個3組成2*2,故power2=2;同時3的個數減1即可
power2 = 2
power3 -= 1
elif mod_type == 2: # 如果餘數爲2,則直接爲2
power2 = 1
# 如果餘數爲0,則不用改變
return int(math.pow(3, power3) * math.pow(2, power2))
這種方法時間複雜度O(1),空間複雜度O(1),因此效果很好:
思路3 動態規劃
求解思路:設S[n]表示長度爲n時的最大乘積,那麼必然有:
S[n] = max{S[n-1], 2*S[n-2], 3*S[n-3], 4*S[n-4],5*S[n-5] ...}
但顯然2*S[n-2]>=4*S[n-4]>5*S[n-5]...,因此保留
S[n] = max{S[n-1], 2*S[n-2], 3*S[n-3]} (n>6)即可
代碼如下:
class Solution:
def cuttingRope(self, n: int) -> int:
s = [1]*59 # 定義初始數組
s[2] = 1
s[3] = 2
s[4] = 4
s[5] = 6
s[6] = 9
for i in range(7,59):
s[i] = max(s[i-1], s[i-3]*3, s[i-2]*2)
return s[n]
但這樣空間複雜度是O(N),時間複雜度是O(N),因此會慢很多:
總結
Python創建1維list: [1]*length即可