Dynamic programming is an optimization technique that builds upon the idea of recursion. It is used to solve problems that have overlapping subproblems and optimal substructure. While plain recursion can lead to redundant calculations, dynamic programming aims to eliminate this redundancy and improve efficiency.
Key differences between dynamic programming and plain recursion:
When to use dynamic programming:
Let's consider the classic example of the Fibonacci sequence to illustrate the difference:
#include <iostream>
#include <unordered_map>
// Plain recursive solution
int fibonacciRecursive(int n) {
if (n <= 1) {
return n;
}
return fibonacciRecursive(n - 1)
+ fibonacciRecursive(n - 2);
}
// Dynamic programming solution with memoization
std::unordered_map<int, int> memoMap;
int fibonacciMemoized(int n) {
if (memoMap.find(n) != memoMap.end()) {
return memoMap[n];
}
if (n <= 1) {
return n;
}
int result = fibonacciMemoized(n - 1)
+ fibonacciMemoized(n - 2);
memoMap[n] = result;
return result;
}
int main() {
int n = 40;
std::cout << "Fibonacci (recursive): "
<< fibonacciRecursive(n) << "\n";
std::cout << "Fibonacci (memoized): "
<< fibonacciMemoized(n) << "\n";
}
Fibonacci (recursive): 102334155
Fibonacci (memoized): 102334155
In the plain recursive solution, the fibonacciRecursive
function calculates the Fibonacci number by recursively calling itself. However, this leads to redundant calculations, as the same Fibonacci numbers are computed multiple times.
On the other hand, the dynamic programming solution with memoization (fibonacciMemoized
) uses an unordered map (memoMap
) to store the previously computed Fibonacci numbers. Before recursively calling itself, it checks if the result is already memoized. If so, it returns the memoized value, avoiding redundant calculations.
The dynamic programming solution is much more efficient, especially for larger values of n
. It eliminates the redundant calculations and significantly reduces the time complexity from exponential to linear.
In summary, dynamic programming is a powerful technique that can be used to optimize recursive solutions by eliminating redundant calculations through memoization or tabulation. It is particularly useful when the problem has overlapping subproblems and optimal substructure. By applying dynamic programming, you can improve the efficiency and scalability of your solutions.
Answers to questions are automatically generated and may not have been reviewed.
An introduction to recursive functions, their use cases, and how to optimize their performance