題目
給定一個正整數 n,將其拆分爲至少兩個正整數的和,並使這些整數的乘積最大化。 返回你可以獲得的最大乘積。
示例 1:
輸入: 2
輸出: 1
解釋: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
輸入: 10
輸出: 36
解釋: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
說明: 你可以假設 n 不小於 2 且不大於 58。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/integer-break
思路
給定正整數,將其拆分爲至少兩個正整數的和。這個問題能否用遞歸的方法來解呢,簡要的分析可以得出答案是肯定的。
可能直接思考分割n比較抽象,我們先來思考一個小一點的數,比如先思考是如何拆分的。下面畫出遞歸樹中的第一次分割:
要分割4,可以分割成1+?(這裏的?表示可能爲一個值,也可能是多個值)、2+?和3+?
其中只有1是不可再分的數字。
對於分割4來說,遞歸樹如上。從上可以看出,存在重複子問題。並且分割1可以作爲我們遞歸的終止條件。
如果仔細分析的話,還可以看出,分割1+3和分割3+1是同樣的問題。因此,這裏我們只需要分割到n//2+1
即可。
下面畫出分割n的示意圖:
這樣我們就簡要的畫出了分割n的遞歸樹。下面我們先用遞歸的方法來解。
代碼
遞歸
class Solution:
# 定義遞歸方法
def breakInteger(self,n):
if n == 1:
return 1
max_result = -1
for i in range(1, int(n//2) + 1): #從1分割到 n//2 + 1
max_result = max(i * (n - i), i * self.breakInteger(n - i), max_result)
return max_result
def integerBreak(self, n: int) -> int:
return self.breakInteger(n)
上面我們分析得知,可以通過從1分割到 n//2 + 1
來加速算法。
重點來看下這段代碼:
max_result = max(i * (n - i), i * self.breakInteger(n - i), max_result)
max_result = -1
初始化爲-1
。然後比較當前最大值、直接用i * (n-i)
(就是說不對n-i
進行分割)、i * breakInteger(n - i)
(對n-i
進行分割後的最大值)三者之間的最大值,覆蓋到max_result
中。
最終返回最大值即可,下面看下提交結果。
果然遞歸的方式會超時。
但是我們不慌,因爲我們會改寫成記憶化搜索了(參閱LeetCode刷題之動態規劃思想)。
記憶化搜索
dp = {}
class Solution:
def breakInteger(self,n):
if n == 1:
return 1
if n not in dp:
max_result = -1
for i in range(1, int(n//2) + 1):
max_result = max(i * (n - i), i * self.breakInteger(n - i), max_result)
dp[n] = max_result
return dp[n]
def integerBreak(self, n: int) -> int:
return self.breakInteger(n)
改寫成記憶化搜索也很簡單,保存對傳入的從參數n
進行分割的結果即可。
動態規劃
最後改寫成動態規劃的方式。
class Solution:
def integerBreak(self, n: int) -> int:
# 因爲n不大於58,我們可以用一個列表來保存,dp[1]=1作爲已知條件,值爲-1表示未計算過
dp = [1] * 2 + [-1] * (n-1) #dp[0]=1 ,dp[1] = 1, dp[2]到dp[n] = -1
for i in range(2, n + 1): # i從2到n
# 依次計算出dp[i]
for j in range(1,int(i/2)+1): # j從1到 i/2 + 1
# 拆分爲j 和 (i-j)
dp[i] = max(dp[i], j * (i - j), j * dp[i - j]) #因爲i-j < i的,而dp[i]在之前已經計算過了
return dp[n]
這裏用了兩個循環,依次計算出2到n的分割最大值。
外層循環是2到n;內層循環用1到 i/2 + 1
去分割i
。
這個題目動態規劃的解法還沒有記憶化搜索快。
在Python2中運行時間還是不錯的。
在做完全平方數這個問題,自己寫的解法需要幾秒鐘,不知道哪裏寫錯了,就去看官方解法的時候,看到了這樣一句話。
在LeetCode中提交時間Python3不知道爲啥運行的時間超過Python2。 因此我嘗試用Python2提交了一下,果然如此。
哈,以後就用Python2來寫了。