Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 29

Identifying Optimal Substructure and Overlapping Subproblems

Recommended resources

Hello! Welcome to your first lesson on Dynamic Programming.

In our last module, we explored algorithms for finding Minimum Spanning Trees, culminating with Prim's algorithm. We saw how a "greedy" choice at each step could lead to a globally optimal solution. Today, we pivot to a new and powerful algorithmic paradigm: Dynamic Programming (DP). As we previewed, DP is a technique for optimizing complex problems by breaking them down and reusing solutions to subproblems.

Your goal for this lesson is to learn how to identify the two fundamental properties a problem must have to be a candidate for a DP solution: optimal substructure and overlapping subproblems. Understanding these concepts is the essential first step before writing any DP code.

1. What is Dynamic Programming?

At its core, Dynamic Programming is an optimization technique. It's not a specific algorithm, but rather a way of thinking about and solving problems. It's particularly effective for problems where a naive recursive solution would be incredibly inefficient due to re-computing the same work over and over.

The name itself can be a bit misleading. It was coined by Richard Bellman in the 1950s. Here, "programming" refers to "planning" or "decision-making" in a mathematical sense, not writing code. "Dynamic" was chosen to reflect the time-varying nature of the problems.

Let's start with a formal definition and a little history.

A Beginner's Guide to Dynamic Programming

This video from Matt Guest, 'A Beginner's Guide to Dynamic Programming', offers a concise, high-level overview of what DP is and why it's named that way.

Watch from 00:52 to 01:39. Focus on the core definition: breaking a complicated problem into smaller, overlapping subproblems and using their solutions to build the final answer.

The key takeaway is that DP is about being clever: solve each smaller piece of the puzzle only once, save the answer, and look it up if you need it again.


2. The Two Conditions for Dynamic Programming

A problem isn't automatically a good fit for DP. It must satisfy two specific conditions. If a problem exhibits both of these properties, you can be highly confident that a DP approach is viable and will likely offer significant performance improvements over a simple recursive solution.

Characteristics of DP Problems Venn Diagram
A problem is suitable for Dynamic Programming only if it has both optimal substructure and overlapping subproblems. Image courtesy of InterviewBit.

Let's dissect each of these properties.


3. Property 1: Optimal Substructure

A problem exhibits optimal substructure if an optimal solution to the overall problem can be constructed from the optimal solutions of its subproblems.

This sounds a bit academic, but it's an intuitive concept. Think about finding the shortest driving route from San Francisco to San Diego, which passes through Los Angeles. The shortest route from SF to SD is guaranteed to be composed of the shortest route from SF to LA, followed by the shortest route from LA to SD. The optimal solution to the big problem contains optimal solutions to the smaller subproblems.

The following reading provides an excellent illustration by contrasting a problem that has optimal substructure with one that doesn't.

Optimal Substructure and Overlapping Subproblems

The article 'Optimal Substructure and Overlapping Subproblems' from AfterAcademy clearly defines this property and uses the brilliant contrast between the Shortest Path and Longest Path problems to explain it.

Read the first part of the article, focusing on the 'Optimal Substructure' section. Pay close attention to why the Shortest Path problem has this property, but the (simple) Longest Path problem does not. This distinction is crucial for a deep understanding.

As the article highlights, the Longest Path problem (without cycles) is a great counterexample. The longest path from vertex a to d might not be composed of the longest path from a to an intermediate vertex c and the longest path from c to d. Why? Because the two sub-solutions might share vertices, which is not allowed in a simple path. Combining them would create an invalid path. Therefore, you can't build the global optimal solution from the local optimal solutions in this case.


4. Property 2: Overlapping Subproblems

A problem has overlapping subproblems if a recursive algorithm for solving the problem ends up solving the same subproblems multiple times.

This is where DP's efficiency comes from. Instead of re-calculating these subproblems, we store (or "memoize") their solutions the first time we compute them and simply look them up later.

The classic example used to demonstrate this is the Fibonacci sequence, where fib(n) = fib(n-1) + fib(n-2). Let's visualize the computation for fib(4).

Fibonacci Recursive Tree for Dynamic Programming
This recursion tree for calculating fib(4) shows the repeated computations. `fib(2)` is calculated twice, and `fib(1)` and `fib(0)` are called multiple times. This redundancy is what DP aims to eliminate. Image courtesy of GeeksforGeeks.

As you can see, the work is highly repetitive. This is the "overlapping subproblems" property in action.

Now, let's look at a resource that contrasts this with an algorithm that lacks this property.

Optimal Substructure and Overlapping Subproblems

The same AfterAcademy article we just looked at also has a great section on this second property.

Read the 'Overlapping Subproblems' section. Notice how it uses the Fibonacci sequence as the prime example and contrasts it with Binary Search, where the subproblems are always unique and do not overlap.


5. DP vs. Divide and Conquer

Given your background, you've certainly encountered Divide and Conquer algorithms like Merge Sort or Quicksort. It's useful to distinguish DP from this other powerful paradigm.

Paradigm Subproblems Example
Divide and Conquer Subproblems are independent. Each is solved once and does not overlap with others. Merge Sort: Sorting the left half of an array is completely independent of sorting the right half.
Dynamic Programming Subproblems are overlapping. Solutions are stored to avoid re-computation. Fibonacci Sequence: Calculating fib(5) and fib(4) both require calculating fib(3).

Both paradigms break a large problem into smaller subproblems. The crucial difference lies in the nature of those subproblems. DP is essentially an optimization for recursive problems that suffer from this overlapping, redundant work.


Conclusion

In this lesson, we established the conceptual foundation for Dynamic Programming. You now have the tools to analyze a new problem and determine if it's a good candidate for a DP solution.

Key Takeaways:

  • Dynamic Programming is an optimization technique for solving complex problems by breaking them down into simpler pieces.
  • A problem is suitable for DP if and only if it exhibits both of the following properties:
    1. Optimal Substructure: The optimal solution to the main problem can be constructed from the optimal solutions of its subproblems.
    2. Overlapping Subproblems: A recursive approach solves the same subproblems repeatedly.
  • DP differs from Divide and Conquer primarily in how it handles subproblems: DP is for overlapping subproblems, while Divide and Conquer is for independent ones.

Preview of the Next Lesson:
Now that we can identify a DP problem, the next step is to solve it. In the next lesson, we will take the Fibonacci sequence—our canonical example of a problem with both key properties—and develop a DP solution. We will illustrate the powerful transition from an inefficient, pure recursive function to a highly optimized one using a technique called memoization.