Dynamic Programming in JavaScript

Dynamic programming breaks down complex problems into smaller sub-problems and stores their solutions to avoid redundant calculations. This technique is particularly useful for optimization problems where overlapping sub-problems exist.

Dynamic programming is used where we have problems that can be divided into similar sub-problems so that their results can be re-used. Before solving a sub-problem, the algorithm checks if it has already been solved and stored. The solutions of sub-problems are combined to achieve the optimal solution.

When to Use Dynamic Programming

For a problem to benefit from dynamic programming:

  • The problem should be divisible into smaller overlapping sub-problems
  • An optimal solution can be achieved using optimal solutions of smaller sub-problems
  • The algorithm uses memoization to store computed results

Approaches to Dynamic Programming

Dynamic programming problems can be solved using two main approaches:

  • Bottom-Up (Tabulation): Start by solving the smallest sub-problems first and build up towards the main problem. Results are stored in a table.
  • Top-Down (Memoization): Start with the main problem and break it down. If a sub-problem is already solved, return the stored solution.

Example: Fibonacci Sequence

Let's implement the Fibonacci sequence using both approaches to demonstrate dynamic programming:

Bottom-Up Approach

function fibonacciBottomUp(n) {
    if (n <= 1) return n;
    
    let dp = [0, 1];
    
    for (let i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    
    return dp[n];
}

console.log("Bottom-Up Fibonacci:");
console.log("fib(5) =", fibonacciBottomUp(5));
console.log("fib(10) =", fibonacciBottomUp(10));
Bottom-Up Fibonacci:
fib(5) = 5
fib(10) = 55

Top-Down Approach with Memoization

function fibonacciTopDown(n, memo = {}) {
    if (n <= 1) return n;
    
    // Check if already computed
    if (memo[n]) return memo[n];
    
    // Compute and store result
    memo[n] = fibonacciTopDown(n - 1, memo) + fibonacciTopDown(n - 2, memo);
    
    return memo[n];
}

console.log("Top-Down Fibonacci:");
console.log("fib(5) =", fibonacciTopDown(5));
console.log("fib(10) =", fibonacciTopDown(10));
Top-Down Fibonacci:
fib(5) = 5
fib(10) = 55

Example: Climbing Stairs Problem

Find the number of ways to climb n stairs when you can take either 1 or 2 steps at a time:

function climbStairs(n) {
    if (n <= 2) return n;
    
    let dp = [0, 1, 2];
    
    for (let i = 3; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    
    return dp[n];
}

console.log("Ways to climb stairs:");
console.log("3 stairs:", climbStairs(3));
console.log("5 stairs:", climbStairs(5));
Ways to climb stairs:
3 stairs: 3
5 stairs: 8

Time Complexity Comparison

Approach Time Complexity Space Complexity
Naive Recursion O(2^n) O(n)
Dynamic Programming O(n) O(n)

Key Benefits

  • Eliminates redundant calculations through memoization
  • Significantly reduces time complexity
  • Provides optimal solutions for optimization problems
  • Can be implemented using either iterative or recursive approaches

Conclusion

Dynamic programming is a powerful technique that transforms exponential-time problems into polynomial-time solutions by storing and reusing computed results. It's essential for solving optimization problems efficiently in competitive programming and real-world applications.

Updated on: 2026-03-15T23:18:59+05:30

3K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements