0% found this document useful (0 votes)
7 views21 pages

Introduction to Dynamic Programming

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views21 pages

Introduction to Dynamic Programming

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd

Dynamic Programming

Presented By:
 Abduljabar Mohammed Madey
 Charles Kibet Ng’etich
 Dennis Onyinkwa Nyabaro
 Diero Ajwang
 Edwin Seno
 George Kihara Mburu
 Jeremiah Warui Wamwea
 John Kimani Muragu
 Joyadams Munene
 Marion Jeptoo
 Muriithi Alex Karani
 Nyairo Charles Magati
Introduction to Dynamic
Programming (DP)

 Dynamic programming is a method used to solve problems by


breaking them down into smaller, overlapping subproblems.

 Each subproblem is solved only once and stored for future use,
avoiding repeated calculations and improving efficiency.

 Core Concept: Instead of recalculating the same values


repeatedly, we remember previously computed results and reuse
them when needed.
The problem can be broken into
overlapping subproblems
When to Use
Dynamic The problem exhibits optimal
substructure (optimal solution
Programmin contains optimal solutions to
subproblems)
g:
A brute-force recursive solution would
involve redundant calculations
Key Principles of Dynamic
Programming

 Optimal Substructure
A problem has optimal substructure if an optimal solution can be
constructed from optimal solutions of its subproblems.

For example, the shortest path from A to C through B consists of the


shortest path from A to B plus the shortest path from B to C.
Key Principles of Dynamic
Programming(cont)

 Overlapping Subproblems
Unlike divide-and-conquer algorithms (which solve independent
subproblems), DP solves problems in which the same subproblems
are solved multiple times.
Example: Fibonacci Sequence
Formula: F(n) = F(n-1) + F(n-2)
Without optimization, computing F(5) leads to recalculating values
like F(3) and F(2) multiple times.
The process of DP works in three phases:

1 2 3
Break Down: We split a Solve and Store: We solve Reuse Solutions: When
big, complicated problem each smaller problem, and we encounter the same
into smaller, simpler the answer is saved. This smaller problem again, we
problems that are easier to saved answer is like a don’t have to solve it from
solve. completed puzzle section. scratch. We can reuse the
answer we saved earlier.
There are two main
approaches to
implementing DP:

DP Top-Down (Memoization)-
A recursive approach where
Approache we cache the results of
function calls to avoid
redundant computations.
s Overview
Bottom-Up (Tabulation) -
Tabulation builds up solutions
iteratively from the base
cases.
Memoization
Implementation
Approach
FIBONACCI SERIES
Pseudocode
FUNCTION Fibonacci_memoized (n, memo={})
IF n <=1:
RETURN n;
IF n NOT IN memo:
memo[n] = Fibonacci_memorized(n-1,memo) + Fibonacci_memorized(n-1,memo);
RETURN memo[n]

Explanation:
· This function uses caching (memo) to store previously computed Fibonacci numbers. This prevents recalculating subproblems
multiple times.
Flowchart
Start

n=5
memo = {}

n <=1? Yes Return n

No

n NOT
IN No
memo?

Yes

memo[n] = fib_mem(n-1, memo) + fib_


Return memo[n]
(n-2, memo)

END
Trace for n=5 Fibonacci number
Calls Recursion stack Comment
Call: fib(5) memo = {} [ fib(5) ]
fib(5) needs fib(4) + fib(3) → push fib(4) first. [ fib(4) fib(5) ]
fib(4) → needs fib(3) + fib(2) → push fib(3) [ fib(3) fib(4) fib(5) ]
fib(3) → needs fib(2) + fib(1) → push fib(2) [ fib(2) fib(3) fib(4) fib(5) ]
fib(2) → needs fib(1) + fib(0) → push fib(1) [ fib(1) fib(2) fib(3) fib(4) fib(5) ] Fib(1) returns 1 (base case) and is then popped off the
stack
Push fib(0) (second base case for fib(2)) [ fib(0) fib(2) fib(3) fib(4) fib(5) ] Fib(0) returns 0 (base case) and is then popped off the
stack
[ fib(0) fib(2) fib(3) fib(4) fib(5) ]
Calls Stack contraction & memo growth Comment
[ fib(2) fib(3) fib(4) fib(5) ]
Compute fib(2) = 1 + 0 = 1; Pop fib(2). [ fib(3) fib(4) fib(5) ] memo: {2: 1}
Compute fib(3) = fib(2) + fib(1); (1 from memo [ fib(4) fib(5) ] memo: {2: 1, 3: 2}
+ 1 from base case) Pop fib(3); update memo
Compute fib(4) = fib(3) + fib(2) (sum from what [ fib(5) ] memo: {2: 1, 3: 2, 4: 3}
is in the memo); Pop fib(4); update memo
Finally compute fib(5) = fib(4) + fib(3); sum memo: {2: 1, 3: 2, 4: 3, 5: 5}
from what is in the memo; Pop fib(5); update
memo. Recursion completes
Space and time complexity
analysis

Time Complexity:
· The time taken grows linearly depending on position of the Fibonacci
number to be returned. Hence, time complexity is O(n)

Space Complexity:
· The memory utilized will grow linearly depending on the size of the
Fibonacci number as this will vary the recursion stack size and the memo
table size. Therefore, the space complexity will be O(n)
Advantages and disadvantages
Advantages Disadvantages
· Massive Performance Gain - Eliminates redundant · Memory Overhead - Stores results of every
recalculations of the same subproblems. subproblem. Large problems may consume
significant memory.
· Simplicity and clarity - You retain the natural
· Recursive Stack Depth Limits - Still uses recursion
recursive structure of the problem i.e. easy to write,
hence risk of stack overflow for large inputs
read, and reason about.
· Possible Cache Management Complexity - You
· Automatic Overlapping Subproblem Handling - may need to manage when or how to clear/reset the
Memoization naturally handles overlapping cache. In memory-limited systems, uncontrolled
subproblems ;results are cached the first time and growth of memo can be problematic.
reused automatically.
· On-Demand Computation (Lazy Evaluation) - Only
computes subproblems that are actually needed.
· Reusability - Once computed, the cache (memo) can
be reused for other queries of the same function. This
can be beneficial in interactive or iterative algorithms.
Tabulation
 Does not use recursion
 Bottom-up approach
 Solves subproblems up to the final solution, starting with the base cases.
 The base cases are the initial and simplest subproblems
 Stores subproblems in a table e.g. an array or a map
 How it works
 Step 1: Initialize the Table
 Step 2: Initialize base cases
 Step 3: Perform iterative computation
 Step 4: Extract the final solution to the problem from the last subproblem
to be solved
Example - Fibonacci Sequence
BEGIN
INPUT n

IF n < 2 THEN
RETURN n
ENDIF

Pseudocod CREATE array fib_array OF SIZE n + 1


SET fib_array [0] = 0

e
SET fib_array [1] = 1

FOR i FROM 2 TO n DO
fib_array[i] = fib_array[i - 1] + fib_array[i - 2]
ENDFOR

RETURN fib_array[n]
END
Flowchart
 Without dynamic programming
Time and  Using naive recursion, the complexity of Fibonacci
sequence implementation would be exponential (2^n)

Space  Each recursive call for element n of the sequence


makes two recursive calls: one to n-1 and one to n-2

complexity
 With dynamic programming (Tabulation)
 Time Complexity
 1 + 1 + 1 + 1 + 1 + n + 1 + n + 1 = 2n + 7 =
O(n)
 Time complexity = O(n)
 Space Complexity
 We create a single array of size n + 1
 n + 1 = O(n)
 Space complexity = O(n)
Optimization

 If the goal is just to return the


nth item of the Fibonacci
sequence, a variable of the
last computed subproblem
can be consistently used in
place of an array as the table
 This reduces the space
complexity from linear, O(n),
to constant, O(1)
Advantages and
Disadvantages
Advantages
 No Recursion - thus the program will never exceed allocated memory on the call
stack i.e. No Stack Overflow, even far large values of n
 Easier to Optimize Space
 When using a variable instead of an array for the subproblem storage, memory use of the
program for value storage will always be constant. Allowing efficient use of heap space
allocated to the program
 So, you can reduce from O(n) → O(1) space
 All subproblems are solved exactly once in a predictable sequence, avoiding the
overhead of repeated recursive calls.
 Memory and time are easier to estimate because every subproblem is visited once
 Disadvantages
 It solves all smaller subproblems, even if some aren’t required for the final answer
(Memoization solves only what’s needed.)
 Some problems (e.g. DFS for tree traversal problems) are easier to express
recursively.
Thank you🤝

You might also like