Open-Source Internship opportunity by OpenGenus for programmers. Apply now.
Reading time: 20 minutes | Coding time: 5 minutes
This question is a simple yet confusing problem, and can be asked during a programming interview.
Given a number n, we can divide it in only three parts n/2, n/3 and n/4 recursively (considering only integer part). We have to find the maximum sum that can be made by summing those three parts (n/2 + n/3 + n/4) together.
We will solve this problem in 2 ways:
- Recursive approach O(3^N)
- Dynamic Programming O(N)
For example:
Given n = 16, output is 17,
as we divide it in three parts, we get
{16/2, 16/3, 16/4} = {8, 5, 4}
Its sum is = 8 + 5 + 4 = 17,
now again we break them further,
{8/2, 8/3, 8/4} = {4, 2, 2}, its sum is 8
and further breaking them will end in getting 1 as maximum sum,
thus 8 can give maximum sum as 8 only
Similarly for 5 and 4 also we will be getting 5 and 4 respectively as maximum sum, thus the maximum sum we can get by breaking 16 is 8 + 5 + 4 = 17.
Approach 1 : Recursion
A simple and easy method to solve this problem can be breaking the number recursively and checking to get the maximum sum. We can find, max((break(n/2) + break(n/3) + break(n/4)), n) and return it, break(n) is the function used recursively. It will work, as either the sum of the parts would be maximum or the number itself would be maximum.
Pseudocode
1) Check the number for base condition of 0 and 1.
2) Call the function recursively for all three parts.
3) Return the maximum of sum or the number itself.
Recursive Implementation
# Function to find the maximum sum
def break(n) :
# number should be atleast greater than 2 for recursive calls
if (n == 0 or n == 1) :
return n
# recursively breaking the number and getting maximum as result
return max((break(n // 2) + break(n // 3) + break(n // 4)), n)
# Calling the funtion
n = 16
print(break(n))
Approach 2 : Dynamic Programming
The recursive approach was very simple, but in terms of efficiency it was not best as while breaking the function recursively we were doing some of the operations multiple times. For example : while calculating result for 16, we called the funtion twice for n=4 (one for 16//4 part and another for 8//2 part), we can avoid this problem by using Dynamic Programming. We can store the result obtained for a number in an array and can invoke that result whenever we find that number again.
Pseudocode
1) Initialise the array for size (n+1).
2) Fill the value of base cases inside array
3) Iterate through n and find result for each, retrieving values required from the array
4) Return thr value at position n inside array.
Dynamic programming Implementation
# Function to find the maximum sum
def break(n):
# Initialing an array
stored = [0]*(n+1)
# base conditions covered
stored[0] = 0
stored[1] = 1
# Using bottom-up method to fill array
for i in range(2, n+1):
stored[i] = max(stored[int(i//2)] + stored[int(i/3)] + stored[int(i/4)], i);
return dp[n]
# Calling the funtion
n = 16
print(break(n))
Complexity
The time and space complexity of Dynamic Programming approach are:
- Time Complexity : O(n)
- Space Complexity : O(n) in case of Dynamic programming
- where n is given integer
The time and space complexity of recursive approach are:
- Time Complexity : O(2^n)
- Space Complexity : O(1) in case of Dynamic programming
- where n is given integer
Question
What is the downside of Dynamic programming ?
Further interesting Dynamic Programming Questions to solve