Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
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.
