Hello! Welcome to the first lesson in our module on Dynamic Programming.
In our last lesson, we introduced memoization as a way to optimize recursive algorithms that suffer from solving the same subproblems repeatedly. You learned that this technique, also known as top-down Dynamic Programming, is applicable when a problem has two specific characteristics.
Today, we'll dive deep into those characteristics. Our goal is to master the crucial first step in solving any DP problem: identifying whether a problem is suitable for a dynamic programming approach. By the end of this lesson, you will be able to spot problems that exhibit optimal substructure and overlapping subproblems, which are the two tell-tale signs that DP is the right tool for the job. This skill is foundational for acing DP questions in technical interviews.
1. The Two Pillars of Dynamic Programming
A problem can be solved efficiently using dynamic programming if and only if it exhibits two key properties. Let's define them formally.
A Beginner's Guide to Dynamic Programming
The video 'A Beginner's Guide to Dynamic Programming' by Matt Guest provides a concise and clear explanation of these two properties. We'll start by watching the sections that define them.
Watch from 01:39 to 04:36. Pay attention to how the video explains 'optimal substructure' using a shortest path example and 'overlapping subproblems' using the familiar Fibonacci sequence.
Let's break down what you just saw.
a) Optimal Substructure
A problem has optimal substructure if an optimal solution to the overall problem can be constructed from the optimal solutions of its subproblems.
The shortest path example from the video is a perfect illustration:
- Problem: Find the shortest path from San Francisco to San Diego.
- Subproblems: Find the shortest path from SF to Los Angeles, and the shortest path from LA to San Diego.
- Optimal Substructure: If you combine the shortest path from SF to LA with the shortest path from LA to SD, you are guaranteed to have the shortest path from SF to SD overall. The optimal solution to the big problem is built from the optimal solutions of the smaller ones.
A great heuristic for spotting this property is to ask yourself: "Can I solve this problem recursively?" If you can define the solution for a problem of size n in terms of solutions for problems of a smaller size (e.g., n-1, n-2), it likely has optimal substructure.
b) Overlapping Subproblems
A problem has overlapping subproblems if a recursive algorithm solves the same subproblems over and over again, rather than generating new subproblems at each step.
As you saw in the last lesson and again in the video, the recursive solution for Fibonacci numbers is the classic example. Calculating fib(5) requires calculating fib(4) and fib(3). But the fib(4) calculation also requires calculating fib(3), leading to redundant computations. The recursion tree clearly shows these "overlapping" calls.
It is the presence of both of these properties that makes a problem a candidate for dynamic programming.

2. How to Recognize a DP Problem in an Interview
Now for the practical part: you're in an interview, you get a problem, and the clock is ticking. How do you quickly and confidently determine if it's a DP problem?
There are several strong signals to look for.
Dynamic Programming Interview Questions & Tips
The article 'Dynamic Programming Interview Questions & Tips' from interviewing.io provides excellent, practical heuristics for identifying DP problems in an interview setting.
Read the sections 'Heuristics for Identifying Dynamic Programming Problems' and 'Optimal Substructure and Overlapping Subproblems'. This will give you a practical checklist to run through when you first encounter a problem.
Let's consolidate these ideas into a three-step process.
Step 1: Look for Keywords and Problem Types
Many DP problems fall into two categories. Being able to spot the category is a strong first signal.
Dynamic Programming — [Notes]. · DP? - Tarun Jain
This article, 'Dynamic Programming — [Notes]', by Tarun Jain, provides a clean breakdown of these two problem categories with examples.
Read the subsections 'Optimization problems' and 'Counting Problem' under the main heading 'How do we recognize a DP problem?'. Focus on the types of questions being asked in the examples.
To summarize, be on the lookout for problems that ask you to:
- Find an optimal value: Look for keywords like "maximum," "minimum," "longest," "shortest," "best," etc.
- Example: What is the longest common subsequence? What is the minimum number of coins to make change?
- Count the number of ways: Look for keywords like "how many ways," "total number of possibilities," "count all," etc.
- Example: How many ways are there to climb
nstairs? Count the number of unique paths in a grid.
- Example: How many ways are there to climb
If your problem fits one of these descriptions, move to the next step.
Step 2: Formulate a Brute-Force Recursive Solution
Try to define the problem in terms of itself. This is your test for optimal substructure.
- For the "Climbing Stairs" problem:
ways(n) = ways(n-1) + ways(n-2). The solution fornsteps depends on the solutions forn-1andn-2steps. - For the "Longest Common Subsequence" of strings
AandB: The solution depends on what you do with the last characters ofAandB, leading to subproblems with shorter strings.
If you can write down a recurrence relation, you've confirmed optimal substructure.
Step 3: Draw the Recursion Tree to Find Overlaps
This is the definitive test for overlapping subproblems. Take your recursive relation from Step 2 and draw the tree of function calls for a small example.
As the article by Tarun Jain notes, this is a critical step:
"If we have an optimization or counting problem, then one of the simple ideas would be to design a recursive solution, draw the recursion tree for some sample input and identify the repeated sub-problems scenario. If subproblems are repeated then the given problem can be solved using dynamic programming."
If you see the same function call (e.g., fib(3)) appearing in multiple branches of the tree, you have confirmed overlapping subproblems. At this point, you can confidently state to your interviewer: "This problem has optimal substructure and overlapping subproblems, which suggests that a dynamic programming approach would be effective."
Test your understanding!
You are given a grid of numbers. You start at the top-left corner and want to reach the bottom-right corner. You can only move right or down. The "cost" of a path is the sum of the numbers in the cells you visit. The problem is to find the path with the minimum cost.
Does this problem seem suitable for dynamic programming? Justify your answer using the three-step process.
Show answer
Yes, this problem is a classic DP problem. Here's the justification:
- Keywords/Problem Type: It's an optimization problem. The keyword is "minimum" cost. This is a strong signal.
- Recursive Formulation (Optimal Substructure): Let
minCost(row, col)be the minimum cost to reach the cell at(row, col). To get to(row, col), you must have come from either(row-1, col)(above) or(row, col-1)(left). To get the minimum cost path to(row, col), you should take the minimum of the paths from those two cells.
So,minCost(row, col) = grid[row][col] + min(minCost(row-1, col), minCost(row, col-1)).
Since we can define the solution recursively, the problem has optimal substructure. - Recursion Tree (Overlapping Subproblems): If you draw the recursion tree for
minCost(r, c), you'll see thatminCost(r-1, c)andminCost(r, c-1)will both lead to calls forminCost(r-1, c-1)(and other shared subproblems). There is significant overlap.
Since the problem has both optimal substructure and overlapping subproblems, DP is an excellent approach.
3. Common DP Patterns
As you practice, you'll start recognizing entire categories of problems. Being familiar with these patterns is the high-ROI strategy you're looking for, as many interview questions are variations of these classics.
The following video from NeetCode introduces five common DP patterns. For this lesson, we won't focus on the full solution, but on how each problem is broken down into subproblems.
Top 5 Dynamic Programming Patterns for Coding Interviews - For Beginners
The video 'Top 5 Dynamic Programming Patterns for Coding Interviews' is perfect for your interview preparation goal. As you watch, focus on how each problem type is deconstructed into smaller, recursive subproblems.
Watch the explanations for the '0/1 Knapsack' (06:44 - 09:41), 'Unbounded Knapsack' (13:05 - 16:48), and 'Longest Common Subsequence' (16:48 - 20:57) patterns. For each one, ask yourself: 'What is the decision being made at each step, and how does that decision lead to a smaller subproblem?'
Let's briefly summarize the subproblem structure for these patterns:
- 0/1 Knapsack: Given an item, the decision is to either include it or skip it.
- If you include item
iwith weightwand valuev, the subproblem becomes finding the optimal value for the remaining capacity and remaining items. - If you skip item
i, the subproblem is finding the optimal value for the same capacity but with the remaining items.
- If you include item
- Longest Common Subsequence (LCS): Given two strings, the decision is based on comparing their last characters.
- If the characters match, they contribute to the LCS. The subproblem is finding the LCS of the strings without those last characters.
- If they don't match, you have two choices: find the LCS by either removing the last character from the first string, or removing it from the second string. The solution is the better of these two subproblems.
Recognizing these fundamental decision-making processes is key to identifying the underlying DP pattern.
Conclusion
Mastering dynamic programming begins with pattern recognition. Today, you learned the theoretical foundation and the practical heuristics for identifying problems where DP is a suitable and efficient strategy.
Key Takeaways:
- A problem is a candidate for dynamic programming if it has both optimal substructure and overlapping subproblems.
- Optimal Substructure means the optimal solution can be built from optimal solutions to smaller subproblems. You can test for this by trying to formulate a recursive solution.
- Overlapping Subproblems means a naive recursive solution would re-compute the same subproblems multiple times. You can test for this by drawing the recursion tree and looking for duplicate nodes.
- In an interview, look for optimization (min/max/longest) or counting ("how many ways") problems as your first clue.
- Common DP patterns like Knapsack and Longest Common Subsequence revolve around making a sequence of decisions that break the problem down into smaller instances.
You now have the diagnostic tools to identify DP problems. In our next lesson, we will build upon this by learning how to convert the recursive, memoized solution you're familiar with into an iterative, bottom-up DP solution, a technique also known as tabulation. This will complete your foundational understanding of the two main DP approaches.