There are npiles 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 ith 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 exactlykcoins optimally.
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:
1
2
3
4
5
6
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.
We use recursion with memoization to explore all ways to pick coins from piles, keeping track of the best sum for each state. At each pile, we can skip it or take coins from the top, and recursively solve for the remaining piles and coins.
classSolution {
public:int maxValueOfCoins(vector<vector<int>>& piles, int k) {
int n = piles.size();
vector<vector<int>> dp(n +1, vector<int>(k +1, -1));
returnhelper(piles, dp, 0, k);
}
private:int helper(const vector<vector<int>>& piles, vector<vector<int>>& dp, int idx, int k) {
if (idx == piles.size() || k ==0) return0;
if (dp[idx][k] !=-1) return dp[idx][k];
int ans = helper(piles, dp, idx +1, k);
int sum =0;
for (int i =0; i < min((int)piles[idx].size(), k); ++i) {
sum += piles[idx][i];
ans = max(ans, sum + helper(piles, dp, idx +1, k - i -1));
}
return dp[idx][k] = ans;
}
};
funcmaxValueOfCoins(piles [][]int, kint) int {
n:= len(piles)
dp:= make([][]int, n+1)
fori:=rangedp {
dp[i] = make([]int, k+1)
forj:=rangedp[i] {
dp[i][j] = -1 }
}
varhelperfunc(idx, remint) inthelper = func(idx, remint) int {
ifidx==n||rem==0 {
return0 }
ifdp[idx][rem] !=-1 {
returndp[idx][rem]
}
ans, sum:=helper(idx+1, rem), 0fori:=0; i < len(piles[idx]) &&i < rem; i++ {
sum+=piles[idx][i]
ans = max(ans, sum+helper(idx+1, rem-i-1))
}
dp[idx][rem] = ansreturnans }
returnhelper(0, k)
}
func max(a, bint) int { ifa > b { returna }; returnb }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
classSolution {
publicintmaxValueOfCoins(List<List<Integer>> piles, int k) {
int n = piles.size();
Integer[][] dp =new Integer[n + 1][k + 1];
return helper(piles, dp, 0, k);
}
privateinthelper(List<List<Integer>> piles, Integer[][] dp, int idx, int k) {
if (idx == piles.size() || k == 0) return 0;
if (dp[idx][k]!=null) return dp[idx][k];
int ans = helper(piles, dp, idx + 1, k);
int sum = 0;
for (int i = 0; i < Math.min(piles.get(idx).size(), k); i++) {
sum += piles.get(idx).get(i);
ans = Math.max(ans, sum + helper(piles, dp, idx + 1, k - i - 1));
}
return dp[idx][k]= ans;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
classSolution {
funmaxValueOfCoins(piles: List<List<Int>>, k: Int): Int {
val n = piles.size
val dp = Array(n + 1) { Array(k + 1) { -1 } }
funhelper(idx: Int, rem: Int): Int {
if (idx == n || rem ==0) return0if (dp[idx][rem] != -1) return dp[idx][rem]
var ans = helper(idx + 1, rem)
var sum = 0for (i in0 until minOf(piles[idx].size, rem)) {
sum += piles[idx][i]
ans = maxOf(ans, sum + helper(idx + 1, rem - i - 1))
}
dp[idx][rem] = ans
return ans
}
return helper(0, k)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from typing import List
classSolution:
defmaxValueOfCoins(self, piles: List[List[int]], k: int) -> int:
n = len(piles)
dp = [[-1] * (k +1) for _ in range(n +1)]
defhelper(idx: int, rem: int) -> int:
if idx == n or rem ==0:
return0if dp[idx][rem] !=-1:
return dp[idx][rem]
ans = helper(idx +1, rem)
s =0for i in range(min(len(piles[idx]), rem)):
s += piles[idx][i]
ans = max(ans, s + helper(idx +1, rem - i -1))
dp[idx][rem] = ans
return ans
return helper(0, k)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
impl Solution {
pubfnmax_value_of_coins(piles: Vec<Vec<i32>>, k: i32) -> i32 {
let n = piles.len();
letmut dp =vec![vec![-1; (k +1) asusize]; n +1];
fnhelper(piles: &Vec<Vec<i32>>, dp: &mut Vec<Vec<i32>>, idx: usize, rem: i32) -> i32 {
if idx == piles.len() || rem ==0 { return0; }
if dp[idx][rem asusize] !=-1 { return dp[idx][rem asusize]; }
letmut ans = helper(piles, dp, idx +1, rem);
letmut sum =0;
for i in0..std::cmp::min(piles[idx].len(), rem asusize) {
sum += piles[idx][i];
ans = std::cmp::max(ans, sum + helper(piles, dp, idx +1, rem - (i asi32) -1));
}
dp[idx][rem asusize] = ans;
ans
}
helper(&piles, &mut dp, 0, k)
}
}
⏰ Time complexity: O(n * k * m) — n = number of piles, k = coins to pick, m = max coins in a pile. For each pile and coin count, we try all possible coins from the pile.
🧺 Space complexity: O(n * k) — DP table stores results for each pile and coin count.
We use dynamic programming to build up the answer iteratively. For each pile and each possible number of coins to pick, we compute the best value by considering all ways to take coins from the current pile and combine with previous results.
Create a DP table dp[i][j] where i is the number of piles considered and j is the number of coins picked.
Initialize dp[0][*] = 0 (no piles, no coins).
For each pile, for each possible number of coins to pick, try all ways to take coins from the current pile (from 0 up to min(j, pile size)).
Update dp[i][j] as the maximum of not taking any coins from the current pile or taking some coins and adding their sum to the best result from previous piles.
Recurrence Relation:
Let dp[i][j] be the max value using first i piles and picking j coins.
1
2
3
4
dp[i][j] = max(
dp[i-1][j],
max(sum of first l coins from piles[i-1] + dp[i-1][j-l]) for l = 1 to min(j, len(piles[i-1]))
)
classSolution {
public:int maxValueOfCoins(vector<vector<int>>& piles, int k) {
int n = piles.size();
vector<vector<int>> dp(n +1, vector<int>(k +1, 0));
for (int i =1; i <= n; ++i) {
for (int j =0; j <= k; ++j) {
int sum =0;
dp[i][j] = dp[i-1][j];
for (int l =1; l <= min(j, (int)piles[i-1].size()); ++l) {
sum += piles[i-1][l-1];
dp[i][j] = max(dp[i][j], sum + dp[i-1][j-l]);
}
}
}
return dp[n][k];
}
};
classSolution {
publicintmaxValueOfCoins(List<List<Integer>> piles, int k) {
int n = piles.size();
int[][] dp =newint[n + 1][k + 1];
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= k; j++) {
int sum = 0;
dp[i][j]= dp[i-1][j];
for (int l = 1; l <= Math.min(j, piles.get(i-1).size()); l++) {
sum += piles.get(i-1).get(l-1);
dp[i][j]= Math.max(dp[i][j], sum + dp[i-1][j-l]);
}
}
}
return dp[n][k];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
classSolution {
funmaxValueOfCoins(piles: List<List<Int>>, k: Int): Int {
val n = piles.size
val dp = Array(n + 1) { IntArray(k + 1) }
for (i in1..n) {
for (j in0..k) {
var sum = 0 dp[i][j] = dp[i-1][j]
for (l in1..minOf(j, piles[i-1].size)) {
sum += piles[i-1][l-1]
dp[i][j] = maxOf(dp[i][j], sum + dp[i-1][j-l])
}
}
}
return dp[n][k]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
from typing import List
classSolution:
defmaxValueOfCoins(self, piles: List[List[int]], k: int) -> int:
n = len(piles)
dp = [[0] * (k +1) for _ in range(n +1)]
for i in range(1, n +1):
for j in range(k +1):
s =0 dp[i][j] = dp[i-1][j]
for l in range(1, min(j, len(piles[i-1])) +1):
s += piles[i-1][l-1]
dp[i][j] = max(dp[i][j], s + dp[i-1][j-l])
return dp[n][k]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
impl Solution {
pubfnmax_value_of_coins(piles: Vec<Vec<i32>>, k: i32) -> i32 {
let n = piles.len();
let k = k asusize;
letmut dp =vec![vec![0; k +1]; n +1];
for i in1..=n {
for j in0..=k {
letmut sum =0;
dp[i][j] = dp[i-1][j];
for l in1..=std::cmp::min(j, piles[i-1].len()) {
sum += piles[i-1][l-1];
dp[i][j] = std::cmp::max(dp[i][j], sum + dp[i-1][j-l]);
}
}
}
dp[n][k]
}
}
⏰ Time complexity: O(n * k * m) — n = number of piles, k = coins to pick, m = max coins in a pile. For each pile and coin count, we try all possible coins from the pile.
🧺 Space complexity: O(n * k) — DP table stores results for each pile and coin count.