343. Integer Break
MediumDescription
給定正整數
n(n >= 2),將它拆分為至少兩個正整數的和,使這些正整數的乘積最大化。回傳最大乘積。
Example:
Input: n = 10 Output: 36
Intuition#
數學上盡量拆成 3 是最優的;DP 上對每個數嘗試所有可能的第一刀位置。
dp[i]= 把i拆分後能得到的最大乘積- 對每個
j(1 到 i-1),可以選擇繼續拆i-j或不拆 - 狀態轉移:
dp[i] = max(j * (i-j), j * dp[i-j])for allj - 數學解法:盡量拆成 3,因為 3 的分解效率最高
Approaches#
1: Bottom-Up DP#
- 概念: 對每個數嘗試所有切割位置,取最大乘積
- 時間複雜度:
O(n^2) - 空間複雜度:
O(n)
class Solution {
fun integerBreak(n: Int): Int {
val dp = IntArray(n + 1)
dp[1] = 1
for (i in 2..n) {
for (j in 1 until i) {
dp[i] = maxOf(dp[i], j * (i - j), j * dp[i - j])
}
}
return dp[n]
}
}⭐2: Math (Greedy with 3s)#
- 概念: 盡量拆成 3,餘 1 時改用 2+2,餘 2 時保留
- 時間複雜度:
O(1) - 空間複雜度:
O(1)
class Solution {
fun integerBreak(n: Int): Int {
if (n == 2) return 1
if (n == 3) return 2
var result = 1
var rem = n
while (rem > 4) {
result *= 3
rem -= 3
}
return result * rem
}
}🔑 Takeaways#
- Pattern: 最優分割 DP — 嘗試所有分割點,子問題可以選擇繼續分或不分
- 關鍵技巧: 數學上
e ≈ 2.718是最優分割因子,離散化後 3 最佳;注意dp[i]的含義是「拆分後的最大乘積」,而j * (i-j)考慮的是不再拆分i-j的情況