Hello! Welcome to the next lesson in our module on "Algorithms: Sorting, Searching, and Design."
Introduction
In our last lesson, we delved into powerful "divide and conquer" algorithms like Merge Sort and Quick Sort. You learned how they break a large problem into smaller, independent subproblems, solve them recursively, and then combine the results. This approach gave us a significant performance boost, moving from to .
Today, we will explore another, even more powerful algorithmic paradigm called Dynamic Programming (DP). Like "divide and conquer," DP also involves breaking down problems. However, it is specifically designed for problems where the subproblems are not independent—they overlap.
Your learning outcome for this lesson is to: Describe the principles of dynamic programming (optimal substructure, overlapping subproblems).
By the end of this lesson, you will be able to identify the two key characteristics a problem must have to be solvable with Dynamic Programming. This conceptual foundation is essential for your GATE preparation and will be the basis for our next lesson, where we'll start implementing DP solutions.
What is Dynamic Programming?
At its core, Dynamic Programming is an optimization technique. It's about solving a complex problem by breaking it down into a collection of simpler subproblems, solving each of those subproblems just once, and storing their solutions. The next time the same subproblem occurs, instead of recomputing its solution, you simply look up the previously computed solution.
A great way to think about it is "remembering the past to solve the future faster."
To get a simple, intuitive definition, let's watch a short clip.
Dynamic Programming For Beginners
The video 'Dynamic Programming For Beginners' from the Kantan Coding channel provides a very clear, layman's definition of DP.
Watch the section from 02:28 to 03:11. Focus on the core idea of breaking down a problem and reusing solutions.
The crucial difference from the Merge Sort we saw previously is this idea of "reusing solutions." In Merge Sort, the subproblems (sorting the left half and right half of an array) are distinct and don't overlap. In DP, the subproblems are intertwined, and we solve the same ones multiple times if we're not careful.
The Two Core Principles of Dynamic Programming
For a problem to be a candidate for a Dynamic Programming solution, it must exhibit two fundamental properties:
- Optimal Substructure
- Overlapping Subproblems
A problem must have both of these characteristics. If it only has an optimal substructure, a simpler recursive or greedy algorithm might be sufficient. If it has overlapping subproblems without an optimal substructure, DP won't lead to a correct solution.

To get a formal definition of these two concepts, take a quick look at the following resource.
Overview of Dynamic Programming
The article 'Overview of Dynamic Programming' from Codefinity provides concise definitions of our two key concepts.
Read the two bullet points under the heading 'Key Concepts in Dynamic Programming'. This will give you a clear, textual definition of both principles.
Now, let's explore each of these principles in more detail with examples.
1. Optimal Substructure
A problem has an optimal substructure if the optimal solution to the whole problem can be constructed from the optimal solutions of its subproblems.
This might sound familiar because this is the same property we saw in "divide and conquer" algorithms. Let's look at an intuitive example.
A Beginner's Guide to Dynamic Programming
The video 'A Beginner's Guide to Dynamic Programming' by Matt Guest explains optimal substructure using a very intuitive shortest-path problem.
Watch from 01:28 to 02:30. Notice how the overall shortest path is naturally composed of the shortest paths of its segments.
As the video showed, if the shortest path from San Francisco to San Diego goes through Los Angeles, then the path used from SF to LA must be the shortest path between those two cities. You can't have an overall optimal solution that uses a suboptimal solution for one of its parts.
The Fibonacci sequence is another classic example. The solution to Fib(n) is Fib(n-1) + Fib(n-2). The solution to the main problem is constructed directly from the solutions to its subproblems.
2. Overlapping Subproblems
This is the property that truly distinguishes Dynamic Programming problems. It means that a naive recursive solution would solve the same subproblems repeatedly.
Let's use the Fibonacci sequence again. To calculate Fib(5), a simple recursive algorithm would work like this:
Fib(5)callsFib(4)andFib(3)Fib(4)callsFib(3)andFib(2)Fib(3)callsFib(2)andFib(1)
Notice that Fib(3) is being calculated twice, once as a direct subproblem of Fib(5) and again as a subproblem of Fib(4). Fib(2) will be calculated three times! This is a huge waste of computation. These repeated calculations are the "overlapping subproblems."
This recursion tree illustrates the problem perfectly.

To see this explained visually, let's return to the Kantan Coding video.
Dynamic Programming For Beginners
This clip visually demonstrates the overlapping subproblems in the Fibonacci recursion tree.
Watch from 05:41 to 07:00. The presenter highlights the exact subproblems that are being solved more than once.
This redundancy is exactly what Dynamic Programming aims to eliminate by storing the result of each subproblem the first time it's calculated.
Test your understanding!
Consider calculating Fib(6) recursively. How many times would the subproblem Fib(2) be calculated?
Hint: You can draw a recursion tree similar to the one above.Fib(6) -> Fib(5) + Fib(4)Fib(5) -> Fib(4) + Fib(3)Fib(4) -> Fib(3) + Fib(2)
Show answer
Let's trace the calls:
Fib(6)callsFib(5)andFib(4).- The call to
Fib(5)will eventually lead to a call forFib(2). - The call to
Fib(4)will also lead to a call forFib(2). - Let's break it down further:
Fib(6)callsFib(5)which callsFib(4)which callsFib(3)which callsFib(2). (1st time)Fib(6)callsFib(5)which callsFib(4)which callsFib(2). (2nd time)Fib(6)callsFib(5)which callsFib(3)which callsFib(2). (3rd time)Fib(6)callsFib(4)which callsFib(3)which callsFib(2). (4th time)Fib(6)callsFib(4)which callsFib(2). (5th time)
So, Fib(2) would be calculated 5 times. This shows how quickly the number of redundant calculations grows!
Why These Principles Lead to Optimization
The presence of overlapping subproblems in a recursive solution almost always leads to an exponential time complexity, , because the number of function calls grows exponentially with the input size n.
By identifying that a problem has both optimal substructure and overlapping subproblems, we know we can apply DP. By storing the results of subproblems (a process we will later call memoization or tabulation), we ensure each subproblem is only computed once. This typically reduces the time complexity from exponential to polynomial (e.g., or ), which is a massive improvement.
Dynamic Programming For Beginners
This final clip explains why the overlapping subproblems make the naive recursive solution so inefficient.
Watch from 07:45 to 08:35 to understand how the repeated work leads to exponential time complexity and why DP is necessary.
Conclusion
In this lesson, we established the conceptual groundwork for Dynamic Programming, a critical topic for your GATE exam and for computer science in general.
Key Takeaways:
- Dynamic Programming is an optimization technique for problems that can be broken down into smaller, repeating subproblems.
- To be solvable with DP, a problem must have two key properties:
- Optimal Substructure: The optimal solution to the overall problem is composed of the optimal solutions to its subproblems.
- Overlapping Subproblems: A naive recursive solution would compute the same subproblems multiple times, leading to inefficiency.
- DP works by storing the solutions to subproblems to avoid re-computation, drastically improving performance from exponential to polynomial time complexity.
Preview of the Next Lesson:
Now that you know how to identify a DP problem, the next logical step is to learn how to solve one. In the next lesson, we will focus on the two main implementation techniques for Dynamic Programming:
- Memoization (Top-Down Approach)
- Tabulation (Bottom-Up Approach)
We will apply both of these techniques to efficiently solve the Fibonacci sequence problem, turning our theoretical understanding into practical code.