文章目錄
- 題目描述
- 思路分析
- 完整代碼
- 數學
題目描述
給定一個正整數 n ,将其拆分為 k 個 正整數 的和( k >= 2 ),并使這些整數的乘積最大化。
傳回 你可以獲得的最大乘積 。
示例 1:
輸入: n = 2
輸出: 1
解釋: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
輸入: n = 10
輸出: 36
解釋: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
思路分析
先來個例子說明為啥用動态規劃,比如所給數值為n=10。
則可以拆分成 2 + 8 = 10,2無法拆分,8可以繼續拆。實際上可以發現,這裡繼續拆的話就是在找8拆分之後的乘積最大值了。也就是說,後一步依賴于前面的最優解。是以想到用動态規劃,動态規劃就是這樣,這一步依賴于前幾步的最優解,然後用那個狀态轉移方程去一步一步推到結果。
老規矩 dp五步走:
1.确定dp含義:
dp[i] 表示 整數i 的最大乘積。
2.确定遞推公式:
局部的去想這個問題,一個數 i 的拆分情況。
i 被拆分成 j 和 i-j:
i-j 可能都無法繼續拆分,那麼此時乘積就是 j * (i-j)。
i-j 可以繼續拆分,那麼實際上這裡就可以直接使用之前計算過的j的最優解 也就是 dp[i-j],此時乘積就是 j *dp[i-j]。
是以目前數值i的最大值就是上面兩種情況的一種,在加上其本身,一共三種。
dp[i] = max(dp[i], (i - j) * j, dp[i - j] * j);
3.初始化dp數組:
n= 0 和 n=1的時候都是沒法拆的,這倆都定義成0就可以了。
4.确定周遊順序:
顯然 i 是整個周遊的主指針,從 2開始周遊到我們要求的n。
然後就是要拆分的那個j,j從1周遊到i,這塊别寫錯了,假如拆10的話,最多就是1和9。
5.模拟dp數組結果
這一步我通常是省略的,先送出程式,沒通過或者輸出了再回來debug~
細節:
為什麼隻拆了i-j 不考慮拆j?
這一點其實從周遊順序裡就能看出來,第二層的for 裡 j從1周遊到了i,是以j其實是已經從1拆分到了i的,是以不需要考慮拆分他了。
完整代碼
class Solution:
def integerBreak(self, n: int) -> int:
dp = [0] * (n+1)
dp[0] = dp[1] = 0
for i in range(2,n+1):
for j in range(1,i):
dp[i] = max(dp[i],j*(i-j),j*dp[i-j])
return dp[-1]
數學
class Solution:
def integerBreak(self, n: int) -> int:
res = 1
if n == 2:
return 1
if n ==3 :
return 2
if n == 4:
return 4
while n > 4:
res *=3
n -=3
res *= n
return res