面試題14 I: 剪繩子 (Python36)

給你一根長度爲 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.)

具體的數學證明見該鏈接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/mian-shi-ti-14-i-jian-sheng-zi-tan-xin-si-xiang-by/

直觀上也可以理解:

假設最優乘積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即可

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章