Maximum Value of K Coins From Piles
Leetcode Daily Challenge (15th April, 2023)
Problem Statement:-
There are n
piles of coins on a table. Each pile consists of a positive number of coins of assorted denominations.
In one move, you can choose any coin on top of any pile, remove it, and add it to your wallet.
Given a list piles
, where piles[i]
is a list of integers denoting the composition of the i<sup>th</sup>
pile from top to bottom, and a positive integer k
, return the maximum total value of coins you can have in your wallet if you choose exactly k
coins optimally.
Link: https://leetcode.com/problems/maximum-value-of-k-coins-from-piles/description/
Problem Explanation with examples:-
Example 1
Input: piles = [[1,100,3],[7,8,9]], k = 2
Output: 101
Explanation:
The above diagram shows the different ways we can choose k coins.
The maximum total we can obtain is 101.
Example 2
Input: piles = [[100],[100],[100],[100],[100],[100],[1,1,1,1,1,1,700]], k = 7
Output: 706
Explanation:
The maximum total can be obtained if we choose all coins from the last pile.
Constraints
n == piles.length
1 <= n <= 1000
1 <= piles[i][j] <= 10<sup>5</sup>
1 <= k <= sum(piles[i].length) <= 2000
Intuition:-
Backtracking is the first thing that comes to mind.
At each step, we can either take the top of the current pile or move to the next pile and take the top of that pile.
We can use memoization to store the results of the subproblems.
The changing parameters here are the index of the current pile and the number of coins we have left.
Solution:-
Get the length of the piles array and store it in a variable n.
Create a recursive function solve(i,coins) which returns the maximum number of coins we can get if we start from the ith pile and have coins coins left.
If i >= n, return 0 as we have reached the end of the piles array.
Create a variable res and initialize it to the result of the recursive call solve(i+1,coins) which means we are not taking the top of the current pile and moving to the next pile.
Create a variable curPile and initialize it to 0.
Create a for loop which iterates from 0 to min(coins,len(piles[i])) and in each iteration, we add piles[i][j] to curPile and update res to the maximum of res and curPile + solve(i+1, coins-j-1). Here, we are taking the top j+1 coins from the current pile and moving to the next pile. We are subtracting j+1 from coins as we have taken j+1 coins from the current pile.
Return res.
Return the result of the recursive call solve(0,k).
Code:-
JAVA Solution
class Solution {
public int maxValueOfCoins(int[][] piles, int k) {
int n = piles.length;
Map<String, Integer> cache = new HashMap<>();
int res = solve(0, k, piles, n, cache);
return res;
}
public int solve(int i, int coins, int[][] piles, int n, Map<String, Integer> cache) {
if (i >= n) {
return 0;
}
String key = i + "," + coins;
if (cache.containsKey(key)) {
return cache.get(key);
}
int res = solve(i + 1, coins, piles, n, cache);
int curPile = 0;
for (int j = 0; j < Math.min(coins, piles[i].length); j++) {
curPile += piles[i][j];
res = Math.max(res, curPile + solve(i + 1, coins - j - 1, piles, n, cache));
}
cache.put(key, res);
return res;
}
}
Python Solution
class Solution:
def maxValueOfCoins(self, piles: List[List[int]], k: int) -> int:
n = len(piles)
@cache
def solve(i,coins):
if i >= n:
return 0
res = solve(i+1,coins)
curPile = 0
for j in range(min(coins,len(piles[i]))):
curPile += piles[i][j]
res = max(res, curPile + solve(i+1, coins-j-1))
return res
return solve(0, k)
Complexity Analysis:-
TIME:-
The time complexity is O(n*k^2), where n is the number of piles and k is the maximum number of coins that can be taken. The recursive function is called for each pile, and in each call, a loop is executed up to k times. Since the function is memoized using a cache, the actual running time will be much lower.
SPACE:-
The space complexity is O(nk) because the cache contains nk entries, one for each unique pair of i and coins. Again, the actual space used will be much lower due to memoization.
References:-
@cache in Python