MCS 275 Spring 2024
Emily Dumas
Reminders and announcements:
This is fib(6)
. Notice how many calls (e.g. fib(3)
) happen multiple times? Each results in more recursion.
It's even worse for fib(n)
with larger n
.
A technique to address this problem:
Let's memoize fib
.
n=35 | n=450 | |
---|---|---|
recursive (naive) | 1.9s | ≫ age of universe |
recursive (memoized) | <0.001s | 0.003s |
iterative | <0.001s | 0.001s |
Measured on my old office PC (2015, Intel i7-6700K) with Python 3.8.5
Another way to measure the cost of a recursive function is to count how many times the function is called.
Let's do this for recursive fib
.
$n$ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|---|
calls | 1 | 1 | 3 | 5 | 9 | 15 | 25 | |
$F_n$ | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 |
fib
is called to
compute fib(n)
. Then
$$T(0)=T(1)=1$$ and $$T(n) = T(n-1) + T(n-2) + 1.$$
Corollary: $T(n) = 2F_{n+1}-1$.
Proof of corollary: Both sequences $T(n)$ and $2F_{n+1}-1$ have the same first two terms, and obey the same recursion relation. Induction.
Corollary: $T(n) = 2F_{n+1}-1$.
Proof of corollary: Let $S(n) = 2F_{n+1}-1$. Then $S(0)=S(1)=1$, and $$\begin{split}S(n) &= 2F_{n+1}-1 = 2(F_{n} + F_{n-1}) - 1\\ &= (2 F_n - 1) + (2 F_{n-1}-1) + 1\\ & = S(n-1) + S(n-2) + 1\end{split}$$ Therefore $S$ and $T$ have the same first two terms, and follow the same recursive definition based on the two previous terms. By induction, the set of $n$ such that $T(n) = 2F_{n+1}-1$ is all of $\mathbb{N}$.
Corollary: Every time we increase $n$ by 1, the naive recursive fib
does $\approx61.8\%$ more work.
(The ratio $F_{n+1}/F_n$ approaches $\frac{1 + \sqrt{5}}{2} \approx 1.61803$.)
How do you solve a maze?
How do you solve a maze?
My guess at your approach:
A formal version of this recursion with backtracking. Start with
Add one more step to the path.
Make a recursive call to see what happens after that.
If the answer is "nothing good", consider a different next step.
Two stop conditions: Dead end or goal.
If goal: Great! Return the path as solution.
If dead end: Return None
to tell whoever called us to try something else (to backtrack).
depth_first_maze_solution
:
Input: a maze and a path under consideration (partial progress toward solution).
None
, continue the loop.)None
.
This method is also called a depth first search for a path through the maze.
Here, depth first means that we always add a new step to the path before considering any other changes (e.g. going back and modifying an earlier step).
Let's explore the Maze
class from maze.py
.
Same suggested references as Lecture 9.