A2SV - Recursion Lecture 2024
A2SV - Recursion Lecture 2024
Recursion
Lecture Flow
1. Pre-requisites
2. Problem definitions
3. Basic Concepts
4. Time and Space Complexity of Data Structure
5. Common pitfalls
6. Practice questions and Resources
7. Quote of the day
Pre-requisites
4
Real Life Example
Imagine you are in a long queue and the reception asks you how many
people there are in the line. How do you count the number of people in
the queue?
5
Brainstorm
6
1 Asking and Aggregating steps
How many
people are 2
How many 4
there? 3
How many people behind
people you including 5
reception behind you yourself? Only Me
Let me
including
check…
yourself?
2 + 1= 3
7
6
There
are 2
Third
people
Second person
First person
person
Stopping
7 case
Can we simulate
this with code?
● Since we are doing
the same thing again
and again let’s use
one function to do
the task
8
Does this work?
def ask(person):
behind = ask(person + 1)
people = behind + 1
return people
9
What happens?
behind = ask(person + 1)
people = behind + 1 behind = ask(person + 1)
people = behind + 1 behind = ask(person + 1)
people = behind + 1 behind = ask(person + 1)
return people
people = behind + 1
return people
return people
return people
10
Does this work?
def ask(person):
if noMorePeople:
return 1
behind = ask(person + 1)
people = behind + 1
return people
11
What happens?
if noMorePeoplen:
return 1 if noMorePeople:
return 1 if noMorePeople:
return 1 if noMorePeople:
behind = ask(person + 1)
return 1
people = behind + 1 behind = ask(person + 1)
people = behind + 1 behind = ask(person + 1)
people = behind + 1 behind = ask(person + 1)
return people
people = behind + 1
return people
return people
return people
12
Real Life Example 2
Imagine some one give you a matryoshka and ask you to count the
number dolls, how would you solve the problem?
Brainstorm
14
Brainstorm
15
Brainstorm
16
Brainstorm
17
Brainstorm
18
Brainstorm
Base Case
return 1
19
Brainstorm
return 1+1
Base Case
return 1
20
Brainstorm
return 1+2
return 2
Base Case
return 1
21
Brainstorm
return 1+3
return 3
return 2
Base Case
return 1
22
Brainstorm
return 1+4
return 4
return 3
return 2
Base Case
return 1
23
Can we simulate
this with code?
● Since we are doing
the same thing again
and again let’s use
one function to do
the task
24
Does this work?
def count(matryoshka):
inside = count(matryoshka.child)
return inside + 1
25
What happens?
inside = count(matryoshka.child)
return inside + 1
inside = count(matryoshka.child)
return inside + 1
inside = count(matryoshka.child)
return inside + 1
• • •
26
How about this?
def count(matryoshka):
if matryoshka.empty:
return 1
inside = count(matryoshka.child)
return inside + 1
27
What happens?
if matryoshka.empty:
return 1
if matryoshka.empty:
inside = count(matryoshka.child) return 1
return inside + 1 if matryoshka.empty:
inside = count(matryoshka.child) return 1
return inside + 1
inside = count(matryoshka.child)
return inside + 1
?
31
Basic components of recursion
● Base case The condition that signals when the function should stop
● Recurrence relation Reduces all cases towards base case. The section
where the function calls itself with modified inputs and state
with currently
32
What were the Base Case, Recursive Relation and The State in the previous
example?
State
def count(matryoshka):
if matryoshka.empty:
return 1 Base Case
inside = count(matryoshka.child)
Recurrence
Relation
return inside + 1
33
Base case
34
Recurrence Relation
35
State
36
Sample Question
Solution
From the above questions we can see that we have two base cases and the
state is the number that is divided by four every time we have recursive call.
Dividing a power of four by four
64 / 16 / 4 / 1
28 / 7 / 1.75 / 0.44
40
Implementation
def isPowerOfFour(self, n: int) -> bool:
# basecases
if n == 1: return True
if n < 1: return False
42
What is the base case and recurrence relation for the above
problem?
43
Base Case
● If n == 1, return 1
● If n == 0, return 0
State
● n
Recurrence Relation
● f(n)=f(n-1)+f(n-2)
44
Implementation
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
47
Example Using Call Stack
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = fib(3)
two = fib(2)
49
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=3
one = fib(2)
two = fib(1)
N=4
one = fib(3)
two = fib(2)
50
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
N=3
one = fib(2)
two = fib(1)
N=4
one = fib(3)
two = fib(2)
51
def fib(n: int) -> int:
if n == 1:
return 1
N=1
return 1
if n == 0:
return 0
N=3
one = fib(2)
two = fib(1)
N=4
one = fib(3)
two = fib(2)
52
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
N=3
one = fib(2)
two = fib(1)
N=4
one = fib(3)
two = fib(2)
53
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
N=3
one = fib(2)
two = fib(1)
N=4
one = fib(3)
two = fib(2)
54
def fib(n: int) -> int:
if n == 1:
return 1
N=0
return 0
if n == 0:
return 0
N=3
one = fib(2)
two = fib(1)
N=4
one = fib(3)
two = fib(2)
55
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
N=3
one = fib(2)
two = fib(1)
N=4
one = fib(3)
two = fib(2)
56
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
N=2
one = fib(n-1) one = 1
two = fib(n-2) two = 0
return one + two
return one + two
N=3
one = fib(2)
two = fib(1)
N=4
one = fib(3)
two = fib(2)
57
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=3
one = 1
two = fib(1)
N=4
one = fib(3)
two = fib(2)
58
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=3
one = 1
two = fib(1)
N=4
one = fib(3)
two = fib(2)
59
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
N=3
one = 1
two = fib(1)
N=4
one = fib(3)
two = fib(2)
60
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = fib(3)
two = fib(2)
61
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = fib(3)
two = fib(2)
62
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = 2
two = fib(2)
63
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = 2
two = fib(2)
64
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = 2
two = fib(2)
65
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
N=4
one = 2
two = fib(2)
66
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = 2
two = fib(2)
67
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = 2
two = fib(2)
68
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
N=4
one = 2
two = fib(2)
69
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = 2
two = fib(2)
70
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = 2
two = fib(2)
71
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = 2
two = 1
72
def fib(n: int) -> int:
if n == 1:
return 1
if n == 0:
return 0
one = fib(n-1)
two = fib(n-2)
N=4
one = 2
two = 1
return 3
73
Using Execution Tree
Step by Step Simulation
Go to this LINK
Depth of the
execution tree
Num of nodes
approximately
: 2n+1 - 1
76
Debugging using the execution tree
● Simulate the code using the
execution tree using pen and
paper by yourself.
● Simulate your code with
recursion simulation sites
● Compare the results
77
Debugging using the call stack and print statements
● Simulate the code
using the call stack N=0 def recursive_fn(state):
return 0 print(“state: “, state)
by yourself using
pen and paper N=2 .
● Use print one = 1 .
two = fib(0)
statements to see if .
your code matches N=3
one = fib(2) print(“result: “, result)
the simulation two = fib(1) return result
N=4
one = fib(3)
two = fib(2)
78
Complexity Analysis
Time Complexity
(Any suggestion?)
There are two parts
● Number of recursive calls
● The complexity of the function
81
How do we find the number of calls?
● Draw the execution tree
● Execution tree is a tree that describes the
flow of execution for the recursive function
● A node represents a call
● The total number of nodes is your final
answer
82
Fib(4)
Facts: 20+1 - 1 4
● Two branching on each
node 3 2
nodes
83
In general
● Let
○ b = number of branches on each node
○ d = depth of the tree
d+1
● Total number of nodes = b -1
84
What is the complexity of the function?
● This is plain time and space complexity
analysis of the inner working of the function
● Are we doing any costly operations in the
function?
85
In Summary
86
Space Complexity
Before we discuss the space complexity, let’s consider these questions
● How does the computer run recursion function?
● How does it know when to return and combine?
87
It uses call stack
88
What is the space complexity of the call
stack?
89
Maximum size of the stack which is maximum
depth of the execution tree
90
Did we forget anything?
91
What about the states and space complexity
of the function?
92
In Summary
N=0
return 0
N=4
one = fib(3)
two = fib(2)
93
Checklist (Ask your instructor, if anything is missing)
❏ You have to be very comfortable with writing out the base case and
recurrence relation of recursive function
❏ You have to be very comfortable with drawing execution tree of a recursion
function
❏ Understanding the execution order using the execution tree
❏ Comfortably analyze the time and space complexity of a recursive function
94
Recursion versus Iteration
95
Recognizing in Questions
● Look for patterns in the question that suggest that the same
operation is being applied to smaller versions of the same
problem.
● Look for base cases or stopping conditions that define when
the recursion should end.
● Searching problems with branching conditions
Things to pay attention
Stack Overflow ?
Occurs when the program uses up the memory assigned to it in the call stack
98
Memory Limit Exceeded
99
Maximum Recursion Depth Exceeded
100
A function with missing base case
return fib(n-1) +
fib(n-2)
101
Wrong recurrence relation
prev = numOfPeopleInQueue(n + 1) + 1
return prev
102
Using list as state
notPick = divideInBuckets(i+1,picked)
picked.append(arr[i])
pick = divideInBuckets(i+1,picked) Passed by
reference
103
Practice Questions
Reverse String
Count Good Numbers
Pascal’s Triangle II
Merge Two Sorted List
Decode String
Predict the Winner
Power of three
Power of four
Resources
● Leetcode Recursion I Card
● Leetcode Recursion II Card
Quote
“In order to understand recursion, one must first
understand recursion.”
Unknown