Persistent Systems Interview Question
Developer Program EngineersCountry: India
Interview Type: Written Test
Nice idea!
I also think that it will work within the time limit.
+1
However, I think instead of building DP table bottom-up, we can do top-down memoization (with hash table). It may save space...
Since any argument to the recursive call will have the form N / (2^i * 3^j), the number of possible distinct arguments is less than log_2(N) * log_3(N). For N <= 1 000 000 000, this upper bound is about 600 only. Therefore using the top-down memorization strategy is a lot better in this case.
I think a recursive with memoization solution would do. To save space, memoization can be implemented with hash table.
Pseudo-code may look like:
long long valueOf(long n){
if (hash[n] != 0) return hash[n];
if (n<4) return n;
long long tmp = max(n, valueOf(n/2) + valueOf(n/3) + valueOf(n/4) );
hash[n] = tmp; // memoizing the tmp result into the hash.
return tmp;
};
The hash table once memoized can be used for different function calls, thus it works efficiently for multiple test cases.
Note that, in this case memoization (top-down) may have better space complexity than using DP table (bottom-up).
Not just better space, but better time too, because we don't necessarily have to calculate the answer for every value in [0, N], but only answers to subproblems that actually occur.
Yes, that's top-down vs. bottom-up.
Recursive with memoization is never worse than bottom-up DP in running time.
It can save space in many cases.
Top-down dp can be a constant factor worse. You probably mean it's no worse asymptotically, though.
I think the key is that this process of trading for smaller coins can bring you more money or less money in an iterative fashion. For example, take a coin of value 24:
24 can be broken into 12, 8, 6.
12 in turn can be broken into 6, 4, 3.
Coins of 8 or 6 or 4 or 3 do not increase in value when breaking them, but by breaking a 24 and then breaking the resulting 12, you get 8 + 6 + 6 + 4 + 3 = 27.
So at each opportunity to either split a coin or trade it for dollars, you have to find the maximum. There are more efficient ways of doing this iteratively or with memo-ization but a simple recursive method only takes a few seconds for n=1,000,000,000. Java:
public static long maxCoinValue(long n) {
if (n < 1)
return 0;
return Math.max(n,
maxCoinValue(n / 2) +
maxCoinValue(n / 3) +
maxCoinValue(n / 4));
}
private static int find(int n, String path) {
int a = n / 2;
int b = n / 3;
int c = n / 4;
int _n = a + b + c;
if (_n <= n) {
System.out.println(path);
return n;
}
int a1 = find(a, path + "/2 - > " + a);
int b1 = find(b, path + "/3 - > " + b);
int c1 = find(c, path + "/4 - > " + c);
return a1 + b1 + c1;
}
#include<cstdio>
#include<map>
using namespace std ;
map< long long int , long long int > h ;
inline long long int rec( long long int f )
{
if( f == 0 )
return 0 ;
long long int a = h[f] ;
if( a == 0 )
{
a= max(f,rec(f/2)+rec(f/3)+rec(f/4));
h[f]=a;
}
return a ;
}
int main( )
{
long long int n ;
while( ~scanf("%lld",&n) )
printf("%lld\n",rec(n)) ;
return 0 ;
}
precompute till 10^6 using D.P.
- neerajlakhotia08 April 18, 2014Then use recursion that stops if n<=1000000
This combination of precomputation + recursion should get it done within the time limit