Hello! In our previous lesson, we moved into two dimensions, tackling the "Unique Paths" problem on a grid. You learned to define a DP state based on grid coordinates, dp[i][j], and derived a recurrence relation based on the allowed movements. This gave you a solid foundation for DP problems where the state corresponds to a physical position.
Today, we will venture into a different, and very common, category of dynamic programming problems. In these problems, the state is not defined by a position on a grid, but by more abstract quantities like a target sum or a remaining capacity. Your goal for this lesson is to learn how to dissect these problems, identify the underlying structure, and formulate the correct DP recurrence relation. We will focus on two canonical examples: the Coin Change problem and the Unbounded Knapsack problem. This is a crucial skill, as formulating the recurrence is the conceptual heart of solving any DP problem.
1. The Coin Change Problem: Counting Combinations
Let's start with a classic: the Coin Change problem.
Problem: You are given an array of distinct integer coin denominations and a total amount of money. Your task is to find the number of combinations of coins that make up that amount. You can assume you have an infinite supply of each kind of coin.
For example, if amount = 5 and coins = {1, 2, 3}, how many ways can we form the sum 5?
- 5 = 1 + 1 + 1 + 1 + 1
- 5 = 1 + 1 + 1 + 2
- 5 = 1 + 1 + 3
- 5 = 1 + 2 + 2
- 5 = 2 + 3
The answer is 5.
To solve this with DP, we need to break it down. The core idea in many DP problems is to make a decision at each step. Let's consider the coins one by one. For the last coin in our list, say a coin with value c, and a target amount A, we have two choices:
- Do Not Include Coin
c: We decide not to use this coin at all. The problem then reduces to finding the number of ways to make amountAusing all the other coins. - Include Coin
c: We decide to use this coin. After using it once, the remaining amount we need to make isA - c. Crucially, because we have an infinite supply, the problem reduces to finding the number of ways to make this new amount,A - c, still having access to the same set of coins (includingc).
This branching decision process can be visualized as a recursion tree.

Formulating the Recurrence
This decision process leads us directly to a recurrence relation. To formalize this, we need to define our DP state. A natural way to capture the subproblem is with two parameters: the coins we are allowed to use, and the amount we need to make.
Let dp[i][a] be the number of ways to make amount a using the first i types of coins (from index 0 to i-1).
Based on our two choices for the -th coin (with value coins[i-1]):
- Case 1 (Do Not Include coin
i-1): The number of ways isdp[i-1][a]. We simply solve the same problem with one fewer coin type. - Case 2 (Include coin
i-1): We use one such coin. The remaining amount isa - coins[i-1]. The number of ways to make this remaining amount isdp[i][a - coins[i-1]]. Notice the first parameter isi, noti-1, because we can still use the same coin again.
Since these two cases are mutually exclusive ways to form the total, we add them up. This gives us our state transition equation.
14.5 Unbounded Knapsack Problem - Hello Algo
This section from "Hello Algo" provides a concise derivation of the recurrence for counting coin combinations.
Please read the section titled "Coin Change Problem II". Focus on the logic explained and the final state transition equation.
The recurrence is:
This holds if a >= coins[i-1]. If a < coins[i-1], we cannot include the current coin, so dp[i][a] = dp[i-1][a].
2. A Variation: Minimizing the Number of Coins
Let's see how changing the objective affects the recurrence. What if instead of counting combinations, we wanted to find the minimum number of coins to make a certain amount?
This variation still relies on the principle of optimal substructure. This principle states that an optimal solution to a problem is composed of optimal solutions to its subproblems.
Dynamic Programming Solution to the Coin Changing ...
This document from Northeastern University gives a formal argument for why the Coin Change problem has optimal substructure. This is a key theoretical justification for using DP.
Read the section titled Characterize the Structure. The proof by contradiction here is a classic way to demonstrate optimal substructure and will deepen your theoretical understanding.
Because the problem has optimal substructure, we can build a recurrence. Let's use our 2D state definition again: dp[i][a] is the minimum number of coins to make amount a using the first i coins.
The choices for the -th coin are the same: include it or not.
- Case 1 (Do Not Include coin
i-1): The minimum number of coins isdp[i-1][a]. - Case 2 (Include coin
i-1): We use one coin (cost: 1) and then need to find the minimum coins for the remaining amounta - coins[i-1]. The total number of coins in this case would be1 + dp[i][a - coins[i-1]].
Since we want the minimum, we take the minimum of these two options.
14.5 Unbounded Knapsack Problem - Hello Algo
This section details the DP approach for the "minimum coins" variant.
Read the breakdown of the state transition. Pay close attention to how the objective (minimizing) and the operation (adding 1 for a selected coin) lead to the new recurrence.
The recurrence relation for this new objective is:
Notice the beautiful parallel: we're still choosing between "not including" and "including" the coin. The only things that changed are the combination operator (+ became min) and the value we add when we include a coin (we add the number of combinations dp[...] in the first case, and simply 1 in the second).
3. The Unbounded Knapsack Problem
The Unbounded Knapsack problem is a famous DP problem that perfectly generalizes the structure we've just seen.
Problem: You are given n items, each with a weight and a value. You have a knapsack that can carry a maximum total weight (its capacity). You can take any number of instances of each item. Your goal is to maximize the total value of the items you put in the knapsack.
This problem is called "unbounded" because the supply of each item is infinite, just like our coins. Let's see how the same logic applies.
DP 23. Unbounded Knapsack | 1-D Array Space Optimised Approach
This video from the "take U forward" channel gives an excellent introduction to the Unbounded Knapsack problem and walks through the logic of formulating its recurrence.
First, watch the introduction from the start to understand the problem statement and how it differs from the standard (0/1) knapsack. Then, carefully follow the derivation of the recurrence relation from writing the recurrence. The speaker clearly explains the "take" and "not take" logic and why the index remains the same in the "take" case.
As the video explains, for any given item i and a remaining knapsack capacity c, our choices are:
- Do Not Take Item
i: We leave the item. The maximum value we can get is found by solving the problem for the firsti-1items with the same capacityc. - Take Item
i: We put one instance of itemiin the knapsack. The value increases byvalue[i], and the remaining capacity decreases toc - weight[i]. The maximum value we can get from the remaining capacity is found by solving the problem, again with access to the firstiitems.
Formulating the Recurrence
Let's define our state: dp[i][c] is the maximum value achievable using the first i items with a knapsack capacity of c.
The recurrence relation follows directly from our choices:
14.5 Unbounded Knapsack Problem - Hello Algo
This resource formalizes the state transition equation for the Unbounded Knapsack problem.
Read the section Dynamic Programming Approach to see the formal recurrence. Compare it to the one for Coin Change—the structure is identical, only the operator (max instead of + or min) and values have changed.
The resulting recurrence is:
This formulation should feel very familiar by now. It highlights a powerful pattern for a whole class of "unbounded" problems. The key is always to identify the choice for the current item and correctly express the resulting subproblems.
Conclusion
In this lesson, you took a significant step forward by learning to formulate DP recurrence relations for problems where the state is not tied to a physical grid. You saw how a consistent thought process—breaking the problem down by considering the choices for one item at a time—can be applied to different objectives and constraints.
Key Takeaways:
- Abstract DP States: For problems like Coin Change or Knapsack, the state is often defined by
dp[i][amount], representing a solution considering the firstiitems for a targetamount. - The Core Choice: The recurrence is typically built around two choices for the current item: "include it" or "don't include it."
- Unbounded vs. Bounded: For "unbounded" problems where items can be reused, the "include" case creates a subproblem on the same number of items (
dp[i][...]), not one fewer (dp[i-1][...]). This is a critical distinction. - General Pattern: The structure
dp[i][a] = op(dp[i-1][a], value + dp[i][a - size])is a powerful template, whereopcan be+,min,max, etc., depending on the problem's goal.
You have now practiced the most important conceptual part of dynamic programming. In our next and final lesson of this module, we will put these recurrences into practice. You will learn how to implement the solutions for Coin Change or Unbounded Knapsack using the bottom-up tabulation method, solidifying your ability to translate DP theory into efficient code.