Link: https://leetcode.com/problems/integer-break/
Solution:
Intuition (DP)
The intuition for the DP solution is pretty simple. We subtract 1-n recursively until n = 0 and return zero. Make sure to handle the edge case when n by itself is greater than any product of its sums. Why?
For example:
n = 1
#the only possible break is [0, 1] and the product is 0
n = 2
#the only possible break is [1, 1] and the product is 1
n = 3
#the best possible break is [2, 1] and the product is 2
Handle these edge cases manually otherwise the recursive function will return n...so for n < 4 return n-1
Implementation (DP)
def integer_break(n):
if n < 4:
return n-1
@cache
def dfs(n, product):
if n == 0:
return product
max_prod = 1
for i in range(1, n+1):
max_prod = max(max_prod, dfs(n-i, product * i))
return max_prod
return dfs(n, 1)
#time: O(n**2)
#memory: O(n)
Intuition (math)
The second approach is a bit more interesting. Turns out that it can be mathematically proven that if we greedily multiply by 3, this will always result in the maximum product! If division by 3 has a remainder of 2, multiply by 2 at the end. If the division by 3 has a remainder of 1, then take away a single multiplication by 3 and multiply by 4 instead!
def integer_break(n):
if n < 4:
return n-1
if n % 3 == 1:
return 3**(n//3 - 1) * 4
if n % 3 == 2:
return 3**(n//3) * 2
else:
return 3**(n//3)
#time: O(logn) because exponentiation is usually logn
#memory: O(1)
Visual
Review 1
I actually remembered that we can greedily take 3’s away from n for the max product. There are some edge cases though.
- If the remainder of
n % 3 == 1
then we take one 3 away and multiply by 4. - If
n % 3 == 2
then take all the 3’s and multiply by 2. - if
n % 3 == 0
take all 3’s. - if
n < 4
returnn-1