Recommended resources
The freely available resources this lesson will direct you to.
- 5 Simple Steps for Solving Dynamic Programming Problemswww.youtube.com
- Lean Dynamic Programming with Animations – Full Course for Beginnerswww.youtube.com
- Dynamic Programming: State + Transition Framework | Leveloplevelop.dev
- Steps to solve a Dynamic Programming Problem - GeeksforGeekswww.geeksforgeeks.org
Welcome to the module on Dynamic Programming! This is often considered one of the most challenging topics in algorithms, but it's also one of the most powerful. My goal is to demystify it for you. We'll build up your understanding from first principles, focusing on a structured way of thinking that you can apply to any problem, which should help manage any "algo phobia."
In previous modules, particularly the one on recursion, you saw how to solve problems by breaking them down into smaller instances of the same problem. Dynamic Programming, or DP, takes this a step further. It's an optimization technique for recursive problems that have a specific characteristic: overlapping subproblems.
In this lesson, you will learn to dissect any dynamic programming problem into four fundamental components. Mastering this framework is the key to turning DP from a source of anxiety into a reliable tool in your problem-solving arsenal.
Your learning outcome for today is to identify the state, transition, base cases, and evaluation order of a dynamic program.
The Problem with Plain Recursion
Let's start with a familiar problem: calculating the Nth Fibonacci number. A naive recursive solution looks something like this:
function fib(n: number): number {
if (n <= 1) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
This is elegant, but terribly inefficient. To see why, let's trace the calls for fib(4):

As you can see, we compute fib(2) twice from scratch. fib(1) is computed three times. This redundancy is the "overlapping subproblems" property. For larger n, the number of repeated computations explodes, leading to an exponential time complexity, roughly . Dynamic programming is all about solving each subproblem just once and storing the result for future use.
A Visual Introduction to the DP Mindset
Before we dive into a formal framework, let's build some intuition. The following video provides a fantastic, animated walkthrough of a classic DP problem—the "climbing stairs" problem. It's very similar to Fibonacci and is a great way to see the core ideas of DP in action.
Lean Dynamic Programming with Animations – Full Course for Beginners
Watch the "Lean Dynamic Programming" video from freeCodeCamp.org. It does an excellent job of showing how a simple problem can be solved recursively, identifying the inefficiency, and then introducing the two main DP techniques—memoization and tabulation—to fix it.
Please watch the segment from the beginning up to the introduction of the Min Cost Climbing Stairs problem, which is roughly the first 14 minutes. Pay close attention to these key moments: Deriving the rule: Notice how the problem is broken down into smaller, related subproblems. This relationship is the core of the DP solution. The inefficiency: The video illustrates the same issue we saw with Fibonacci—the recursion tree has many repeated branches. Memoization: This section introduces the "top-down" approach, where we use recursion but store results in a cache (like a Map or hashmap) to avoid re-computation. Tabulation: This section introduces the "bottom-up" approach, where we use a loop and an array (a "table") to build the solution from the smallest subproblems up to the final answer.
This video gave you a visual sense of the entire process. Now, let's formalize the concepts you just saw into a reusable framework.
The Four Pillars of a Dynamic Program
Every DP solution, whether top-down or bottom-up, is built on four conceptual pillars. If you can define these four things for any given problem, you can solve it.
- State: The state is a set of parameters that uniquely defines a subproblem and its solution. It's the "minimum information you need to make a decision." We often use
dp[i]ordp[i][j]to store the solution for the state defined byior(i, j). - Transition: The transition is the formula or rule that relates the solution of a given state to the solutions of smaller subproblems. This is also called the recurrence relation.
- Base Cases: These are the smallest subproblems that can be solved directly, without depending on any other subproblems. They are the starting points for your calculation.
- Evaluation Order: This is the order in which you solve the subproblems. To calculate the solution for a state, the solutions for all the subproblems it depends on must already be computed. This leads to two main strategies:
- Top-down (Memoization): You start with the main problem and use recursion. The first time you solve a subproblem, you store its result. If you encounter the same subproblem again, you retrieve the stored result instead of re-computing.
- Bottom-up (Tabulation): You start from the base cases and fill out a DP table iteratively. You solve subproblems in a specific order (e.g., increasing
i) until you reach the final solution.

Let's solidify these ideas with a couple of short readings.
Dynamic Programming: State + Transition Framework | Levelop
This article from Levelop provides an excellent, practical breakdown of the most critical parts of the framework: State and Transition. It emphasizes that defining the state clearly is the most important step.
Please read the article from the beginning, focusing on these parts: Read the section What "State" Really Means to understand how to define the dp[i] state. Notice the comparison between Fibonacci and Climbing Stairs—same transition formula, but the meaning of the state is different. Next, read the section on Transitions. This explains the relationship between the state definition and the transition formula. Finally, read the section The Framework I Use Now, which summarizes the process into a clear, 4-step checklist.
The next reading offers another perspective and walks through deriving a transition for a counting problem.
Steps to solve a Dynamic Programming Problem - GeeksforGeeks
This GeeksforGeeks article reinforces the same core ideas and provides a good example of how to derive the transition relationship from scratch.
Start by reading Step 1 and Step 2 to see how to identify DP problems and define the state. The definition of state as a set of "parameters that can uniquely identify a certain position" is very useful. Then, carefully study Step 3, which shows how to think through the dependencies to formulate the transition. Finally, look at the code example and its base cases. Notice how n=0 is a base case representing "one way to form sum 0 (by choosing nothing)" and n<0 is an invalid state.
Applying the Framework: Coin Change
Let's apply this four-part framework to a classic interview problem: Coin Change (LeetCode 322).
Problem: You are given an array of coin denominations and a total amount. Find the fewest number of coins that you need to make up that amount. If it's not possible, return -1. Assume you have an infinite number of each coin.
Example: coins = [1, 2, 5], amount = 11. The answer is 3 (5 + 5 + 1).
Let's break this down.
-
State: What information do we need to calculate for each subproblem? The problem asks for the fewest coins for a given amount. This directly suggests our state.
dp[i]: The minimum number of coins required to make amounti.- Our final answer will be
dp[amount].
-
Transition: How can we compute
dp[i]? To make amounti, our last move must have been to add one of the available coins. Let's say we add a coinc. This is only possible if we have already figured out how to make the amounti - c.- If we use coin
c, the total number of coins would bedp[i - c] + 1. - Since we want the minimum number of coins, we should try this for every coin in our
coinsarray and take the best (smallest) result. - This gives us the transition:
dp[i] = min(dp[i - c] + 1)for everycincoins.
- If we use coin
-
Base Cases: What is the smallest subproblem we can solve directly?
- To make an amount of 0, we need 0 coins. So,
dp[0] = 0. - We can also initialize the rest of the
dparray with a large value (like infinity) to signify that those amounts are not yet reachable. This helps with themincalculation in the transition.
- To make an amount of 0, we need 0 coins. So,
-
Evaluation Order: Since
dp[i]depends on smaller values (dp[i - c]), we should compute thedpvalues for increasing amounts.- We will calculate
dp[1], thendp[2],dp[3], and so on, up todp[amount]. This is a bottom-up (tabulation) approach.
- We will calculate
The article from Levelop that you read earlier includes a full trace of this exact problem. I recommend reviewing it now to see the framework in action.
Dynamic Programming: State + Transition Framework | Levelop
This section of the article provides a step-by-step walkthrough of the Coin Change problem.
Please review the section Walking Through a Real Problem. Pay special attention to the trace table, which shows how the dp array is filled one value at a time.
Recognizing What to Solve For
Identifying the state is often the hardest part. You're essentially defining what the subproblem is. The problem statement itself usually contains strong hints. Here are some common patterns you'll see, which often map directly to the DP state.
5 Simple Steps for Solving Dynamic Programming Problems
The video "5 Simple Steps for Solving Dynamic Programming Problems" concludes with a great summary of common subproblem structures.
Watch the final segment on common subproblems. This will give you a mental checklist for what the state dp[i] or dp[i][j] might represent in different types of problems (e.g., subsequences, intervals, grids).
Key Takeaways
This lesson was a conceptual introduction to Dynamic Programming. The main goal was to equip you with a structured way of thinking, not to have you master coding DP problems just yet.
- Dynamic Programming is an optimization technique for problems with overlapping subproblems and optimal substructure (where an optimal solution can be constructed from optimal solutions to its subproblems).
- Any DP problem can be broken down into four key components:
- State: What does
dp[i]represent? (e.g., a value, a count, a minimum/maximum) - Transition: How do you calculate
dp[i]from previous states? - Base Cases: What are the simplest, known values?
- Evaluation Order: In what sequence do you compute the states? (Top-down or Bottom-up)
- State: What does
- Defining the state clearly is the most critical step. If you can write down what
dp[i]means in a single sentence, you are on the right track.
Next Steps
In the next lesson, we will put this framework into practice. We'll take the recursive solutions you learned to write in Module 6 and convert them into efficient, top-down dynamic programming solutions using memoization. This is a very natural first step into implementing DP.