Dynamic Programming (DP)

Solve optimization problems efficiently with the power of overlapping subproblems and optimal substructure.

What is Dynamic Programming?

Dynamic Programming (DP) is a powerful algorithmic paradigm used to solve problems by breaking them into smaller overlapping subproblems. Instead of solving the same subproblem multiple times, DP stores the results in a table (memoization or tabulation) and reuses them to optimize the overall computation.

Key Concepts in DP

  1. Overlapping Subproblems: The problem can be divided into subproblems that are reused multiple times.
  2. Optimal Substructure: The solution to the main problem can be built from the solutions to its subproblems.

DP Approaches

  1. Top-Down (Memoization):

    • Solve the problem recursively.
    • Store the results of subproblems in a table to avoid redundant calculations.
  2. Bottom-Up (Tabulation):

    • Solve the problem iteratively.
    • Build a solution by solving all subproblems from the smallest to the largest.

Time & Space Complexities

  • Time Complexity: O(n) to O(n*m) (depends on the problem and state space).
  • Space Complexity: Can range from O(n) (space-optimized DP) to O(n*m) (when storing a table of solutions).

When to Use DP

Dynamic Programming is a great choice for problems like:

  • Fibonacci numbers.
  • Longest Common Subsequence (LCS).
  • Knapsack problem.
  • Shortest path in a graph (e.g., Floyd-Warshall, Bellman-Ford).
  • Partitioning problems (e.g., Palindrome Partitioning, Subset Sum).

Code Examples

Below is an example of solving the Fibonacci sequence problem using both approaches.

# Top-Down Approach (Memoization)
def fibonacci(n, memo={}):
    if n <= 1:
        return n
    if n not in memo:
        memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)
    return memo[n]

# Bottom-Up Approach (Tabulation)
def fibonacci_tab(n):
    if n <= 1:
        return n

    dp = [0] * (n + 1)
    dp[1] = 1

    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]

    return dp[n]

# Example usage
n = 10
print(f"Fibonacci({n}) using Memoization: {fibonacci(n)}")
print(f"Fibonacci({n}) using Tabulation: {fibonacci_tab(n)}")

Problems to Solve

Important Problems on DP

1D DP [NeetCode]

2D DP [NeetCode]

Resources