Dynamic Programming in Python
Last Updated :
14 Feb, 2025
Dynamic Programming is a commonly used algorithmic technique used to optimize recursive solutions when same subproblems are called again.
- The core idea behind DP is to store solutions to subproblems so that each is solved only once.
- To solve DP problems, we first write a recursive solution in a way that there are overlapping subproblems in the recursion tree (the recursive function is called with the same parameters multiple times)
- To make sure that a recursive value is computed only once (to improve time taken by algorithm), we store results of the recursive calls.
- There are two ways to store the results, one is top down (or memoization) and other is bottom up (or tabulation).
Approaches of Dynamic Programming (DP) in Python
Dynamic programming in Python can be achieved using two approaches:
1. Top-Down Approach (Memoization):
In the top-down approach, also known as memoization, we keep the solution recursive and add a memoization table to avoid repeated calls of same subproblems.
- Before making any recursive call, we first check if the memoization table already has solution for it.
- After the recursive call is over, we store the solution in the memoization table.
2. Bottom-Up Approach (Tabulation):
In the bottom-up approach, also known as tabulation, we start with the smallest subproblems and gradually build up to the final solution.
- We write an iterative solution (avoid recursion overhead) and build the solution in bottom-up manner.
- We use a dp table where we first fill the solution for base cases and then fill the remaining entries of the table using recursive formula.
- We only use recursive formula on table entries and do not make recursive calls.
Approaches of Dynamic Programming (DP)read more about - When to Use Dynamic Programming (DP)?
Example of Dynamic Programming (DP)
Example 1: Consider the problem of finding the Fibonacci sequence:
Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …
Brute Force Approach
To find the nth Fibonacci number using a brute force approach, you would simply add the (n-1)th and (n-2)th Fibonacci numbers.
Python
# Python program to find
# fibonacci number using recursion.
# Function to find nth fibonacci number
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
if __name__ == "__main__":
n = 5
print(fib(n))
Below is the recursion tree of the above recursive solution.
Nth Term in Fibonacci Series
How will Dynamic Programming (DP) Work?
Let’s us now see the above recursion tree with overlapping subproblems highlighted with same color. We can clearly see that that recursive solution is doing a lot work again and again which is causing the time complexity to be exponential. Imagine time taken for computing a large Fibonacci number.
- Identify Subproblems: Divide the main problem into smaller, independent subproblems, i.e., F(n-1) and F(n-2)
- Store Solutions: Solve each subproblem and store the solution in a table or array so that we do not have to recompute the same again.
- Build Up Solutions: Use the stored solutions to build up the solution to the main problem. For F(n), look up F(n-1) and F(n-2) in the table and add them.
- Avoid Recomputation: By storing solutions, DP ensures that each subproblem (for example, F(2)) is solved only once, reducing computation time.
Using Memoization Approach – O(n) Time and O(n) Space
To achieve this in our example we simply take an memo array initialized to -1. As we make a recursive call, we first check if the value stored in the memo array corresponding to that position is -1. The value -1 indicates that we haven’t calculated it yet and have to recursively compute it. The output must be stored in the memo array so that, next time, if the same value is encountered, it can be directly used from the memo array.
Python
# Python program to find
# fibonacci number using memoization.
def fibRec(n, memo):
# Base case
if n <= 1:
return n
# To check if output already exists
if memo[n] != -1:
return memo[n]
# Calculate and save output for future use
memo[n] = fibRec(n - 1, memo) + \
fibRec(n - 2, memo)
return memo[n]
def fib(n):
memo = [-1] * (n + 1)
return fibRec(n, memo)
n = 5
print(fib(n))
Using Tabulation Approach – O(n) Time and O(n) Space
In this approach, we use an array of size (n + 1), often called dp[], to store Fibonacci numbers. The array is initialized with base values at the appropriate indices, such as dp[0] = 0 and dp[1] = 1. Then, we iteratively calculate Fibonacci values from dp[2] to dp[n] by using the relation dp[i] = dp[i-1] + dp[i-2]. This allows us to efficiently compute Fibonacci numbers in a loop. Finally, the value at dp[n] gives the Fibonacci number for the input n, as each index holds the answer for its corresponding Fibonacci number.
Python
# Python program to find
# fibonacci number using tabulation.
def fibo(n):
dp = [0] * (n + 1)
# Storing the independent values in dp
dp[0] = 0
dp[1] = 1
# Using the bottom-up approach
for i in range(2, n + 1):
dp[i] = dp[i - 1] + dp[i - 2]
return dp[n]
n = 5
print(fibo(n))
Using Space Optimised Approach – O(n) Time and O(1) Space
In the above code, we can see that the current state of any fibonacci number depends only on the previous two values. So we do not need to store the whole table of size n+1 but instead of that we can only store the previous two values.
Python
# Python program to find
# fibonacci number using space optimised.
def fibo(n):
prevPrev, prev, curr = 0, 1, 1
# Using the bottom-up approach
for i in range(2, n + 1):
curr = prev + prevPrev
prevPrev = prev
prev = curr
return curr
n = 5
print(fibo(n))
Common Algorithms that Use DP:
Similar Reads
Functional Programming in Python
Functional programming is a programming paradigm in which we try to bind everything in a pure mathematical functions style. It is a declarative type of programming style. Its main focus is on " what to solve" in contrast to an imperative style where the main focus is "how to solve". It uses expressi
10 min read
Incremental Programming in Python
In incremental systems, every measurement refers to a previously dimensioned position (point-to-point). Incremental dimensions are the distances between two adjacent points. An incremental movement moves A distance based on your current position. Start Small - First of all, start your program small
2 min read
Dynamic Programming meaning in DSA
Dynamic Programming is defined as an algorithmic technique that is used to solve problems by breaking them into smaller subproblems and avoiding repeated calculation of overlapping subproblems and using the property that the solution of the problem depends on the optimal solution of the subproblems
2 min read
Last Minute Notes (LMNs) - Python Programming
Python is a widely-used programming language, celebrated for its simplicity, comprehensive features, and extensive library support. This "Last Minute Notes" article aims to offer a quick, concise overview of essential Python topics, including data types, operators, control flow statements, functions
15+ min read
Python | Implementing Dynamic programming using Dictionary
Dynamic Programming is one way which can be used as an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of subproblems so that we do not have to r
3 min read
__import__() function in Python
__import__() is a built-in function in Python that is used to dynamically import modules. It allows us to import a module using a string name instead of the regular "import" statement. It's useful in cases where the name of the needed module is know to us in the runtime only, then to import those mo
2 min read
Python Foreach: How to Program in Python
Foreach loop is a convenient way to iterate over elements in a collection, such as an array or list. Python, however, does not have a dedicated foreach loop like some other languages (e.g., PHP or JavaScript). We will explore different ways to implement a foreach-like loop in Python, along with exam
3 min read
Metaprogramming with Metaclasses in Python
Metaprogramming in Python lets us write code that can modify or generate other code at runtime. One of the key tools for achieving this is metaclasses, which allow us to control the creation and behavior of classes. What Are Metaclasses?Metaclasses are classes that define how other classes are creat
7 min read
Dynamic Attributes in Python
Dynamic attributes in Python are terminologies for attributes that are defined at runtime, after creating the objects or instances. In Python we call all functions, methods also as an object. So you can define a dynamic instance attribute for nearly anything in Python. Consider the below example for
2 min read
Dictionaries in Python
A Python dictionary is a data structure that stores the value in key: value pairs. Values in a dictionary can be of any data type and can be duplicated, whereas keys can't be repeated and must be immutable. Example: Here, The data is stored in key:value pairs in dictionaries, which makes it easier t
5 min read