↓Skip to main content
  1. LeetCode/

LeetCode 2218: Maximum Value of K Coins From Piles

·2 mins· ·
LeetCode Hard Dynamic-Programming Knapsack Prefix-Sum Array
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: hard First Attempt: 2026-09-14

  • Submissions: Accepted ×5 (2D → 1D, refined step by step)

Approach
#

Coins come off the top of each pile, so taking x coins from a pile always means its top x, worth the pile’s prefix sum prefix[x].

Each pile is a group whose options are “take 0..len(pile) coins”: a grouped knapsack:

dp_i[j] = max over x of dp_{i-1}[j - x] + prefix_i[x]

dp[j] = the best value taking j coins from the first i piles. Start with dp[0] = 0 and negative infinity elsewhere (exactly j coins is not yet possible).

My Solution
#

class Solution:
    def maxValueOfCoins(self, piles: List[List[int]], k: int) -> int:
        NEG = float("-inf")
        dp = [0] + [NEG] * k                       # dp[j]: j coins taken so far
        for pile in piles:
            prefix = [0]
            for v in pile[:k]:                     # at most k coins from one pile
                prefix.append(prefix[-1] + v)
            ndp = [NEG] * (k + 1)
            for j in range(k + 1):
                for x, val in enumerate(prefix):   # take x coins from this pile
                    if x > j:
                        break
                    ndp[j] = max(ndp[j], dp[j - x] + val)
            dp = ndp
        return dp[k]

I started from a 2D dp[i][j] and refined it to 1D with per-pile prefix sums; the fresh ndp keeps one pile from being used twice (running j backwards in place also works).

Complexity
#

Time O(k · Σ min(len(pile), k)), space O(k).

Mistakes to Avoid
#

  • Assuming coins can come from anywhere: only from the top, so values are prefix sums.
  • A pile’s options are mutually exclusive: use a new array or run capacity backwards.

Interview Explanation
#

Coins come from the top of each pile, so taking x is worth the pile’s prefix sum; each pile is a group whose option is how many to take, a grouped knapsack. dp[j] is the best value with j coins taken so far, and each pile updates a new array by trying every count. Time O(k · total coins).

Related

LeetCode 4041: Minimum Operations to Form Subset Sum II
·2 mins
LeetCode Hard Dynamic-Programming Knapsack Breadth-First-Search Array
LeetCode 4041 note: with operations in any order, BFS finds every value a number can become (up to sum) with the fewest steps, then the same grouped 0/1 knapsack as 4040
LeetCode 2585: Number of Ways to Earn Points
·2 mins
LeetCode Hard Dynamic-Programming Knapsack Array
LeetCode 2585 note: a bounded (grouped) knapsack; each question type takes 0 to count questions, with capacity running backwards and the count enumerated inside
LeetCode 410: Split Array Largest Sum
·2 mins
LeetCode Hard Dynamic-Programming Binary-Search Greedy Prefix-Sum Array
LeetCode 410 note: binary search the answer; for a cap mid, greedily fill each segment to count the fewest segments, and mid works if that count is <= k
LeetCode 1246: Palindrome Removal
·2 mins
LeetCode Hard Dynamic-Programming Interval-Dp Array
LeetCode 1246 note: interval DP taking the minimum of removing arr[i] alone, removing equal ends together with the inside, or splitting into two parts
LeetCode 2163: Minimum Difference in Sums After Removal of Elements
·2 mins
LeetCode Hard Dynamic-Programming Heap Array
LeetCode 2163 note: try every boundary k between the two parts; the left takes the n smallest of nums[:k] (a max-heap) and the right the n largest of nums[k:] (a min-heap), one prefix and one suffix pass
LeetCode 4040: Minimum Operations to Form Subset Sum I
·2 mins
LeetCode Medium Dynamic-Programming Knapsack Array
LeetCode 4040 note: with multiplications before divisions, the best is always multiply-only or divide-only; list each number’s reachable values and costs, then run a grouped 0/1 knapsack