0% found this document useful (0 votes)
30 views

Recursive Algorithms

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

Recursive Algorithms

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

Introduction to Algorithms: 6.

006
Massachusetts Institute of Technology
Instructors: Erik Demaine, Jason Ku, and Justin Solomon Lecture 15: Recursive Algorithms

Lecture 15: Recursive Algorithms

How to Solve an Algorithms Problem (Review)


• Reduce to a problem you already know (use data structure or algorithm)
Search Data Structures Sort Algorithms Graph Algorithms
Array Insertion Sort Breadth First Search
Linked List Selection Sort DAG Relaxation (DFS + Topo)
Dynamic Array Merge Sort Dijkstra
Sorted Array Counting Sort Bellman-Ford
Direct-Access Array Radix Sort Johnson
Hash Table AVL Sort
AVL Tree Heap Sort
Binary Heap
• Design your own recursive algorithm
– Constant-sized program to solve arbitrary input
– Need looping or recursion, analyze by induction
– Recursive function call: vertex in a graph, directed edge from A → B if B calls A
– Dependency graph of recursive calls must be acyclic (if can terminate)
– Classify based on shape of graph
Class Graph
Brute Force Star
Decrease & Conquer Chain
Divide & Conquer Tree
Dynamic Programming DAG
Greedy/Incremental Subgraph

– Hard part is thinking inductively to construct recurrence on subproblems


– How to solve a problem recursively (SRT BOT)
1. Subproblem definition
2. Relate subproblem solutions recursively
3. Topological order on subproblems (⇒ subproblem DAG)
4. Base cases of relation
5. Original problem solution via subproblem(s)
6. Time analysis
2 Lecture 15: Recursive Algorithms

Merge Sort in SRT BOT Framework


• Merge sorting an array A of n elements can be expressed in SRT BOT as follows:

– Subproblems: S(i, j) = sorted array on elements of A[i : j] for 0 ≤ i ≤ j ≤ n


– Relation: S(i, j) = merge(S(i, m), S(m, j)) where m = b(i + j)/2c
– Topo. order: Increasing j − i
– Base cases: S(i, i + 1) = [A[i]]
– Original: S(0, n)
– Time: T (n) = 2 T (n/2) + O(n) = O(n lg n)

• In this case, subproblem DAG is a tree (divide & conquer)

Fibonacci Numbers
• Suppose we want to compute the nth Fibonacci number Fn

• Subproblems: F (i) = the ith Fibonacci number Fi for i ∈ {0, 1, . . . , n}

• Relation: F (i) = F (i − 1) + F (i − 2) (definition of Fibonacci numbers)

• Topo. order: Increasing i

• Base cases: F (0) = 0, F (1) = 1

• Original prob.: F (n)


1 def fib(n):
2 if n < 2: return n # base case
3 return fib(n - 1) + fib(n - 2) # recurrence

• Divide and conquer implies a tree of recursive calls (draw tree)

• Time: T (n) = T (n − 1) + T (n − 2) + O(1) > 2T (n − 2), T (n) = Ω(2n/2 ) exponential... :(

• Subproblem F (k) computed more than once! (F (n − k) times)

• Can we avoid this waste?


Lecture 15: Recursive Algorithms 3

Re-using Subproblem Solutions


• Draw subproblem dependencies as a DAG

• To solve, either:

– Top down: record subproblem solutions in a memo and re-use


(recursion + memoization)
– Bottom up: solve subproblems in topological sort order (usually via loops)

• For Fibonacci, n + 1 subproblems (vertices) and < 2n dependencies (edges)

• Time to compute is then O(n) additions

1 # recursive solution (top down)


2 def fib(n):
3 memo = {}
4 def F(i):
5 if i < 2: return i # base cases
6 if i not in memo: # check memo
7 memo[i] = F(i - 1) + F(i - 2) # relation
8 return memo[i]
9 return F(n) # original

1 # iterative solution (bottom up)


2 def fib(n):
3 F = {}
4 F[0], F[1] = 0, 1 # base cases
5 for i in range(2, n + 1): # topological order
6 F[i] = F[i - 1] + F[i - 2] # relation
7 return F[n] # original

• A subtlety is that Fibonacci numbers grow to Θ(n) bits long, potentially  word size w

• Each addition costs O(dn/we) time

• So total cost is O(ndn/we) = O(n + n2 /w) time


4 Lecture 15: Recursive Algorithms

Dynamic Programming
• Weird name coined by Richard Bellman

– Wanted government funding, needed cool name to disguise doing mathematics!


– Updating (dynamic) a plan or schedule (program)

• Existence of recursive solution implies decomposable subproblems1

• Recursive algorithm implies a graph of computation

• Dynamic programming if subproblem dependencies overlap (DAG, in-degree > 1)

• “Recurse but re-use” (Top down: record and lookup subproblem solutions)

• “Careful brute force” (Bottom up: do each subproblem in order)

• Often useful for counting/optimization problems: almost trivially correct recurrences

How to Solve a Problem Recursively (SRT BOT)


1. Subproblem definition subproblem x ∈ X

• Describe the meaning of a subproblem in words, in terms of parameters


• Often subsets of input: prefixes, suffixes, contiguous substrings of a sequence
• Often record partial state: add subproblems by incrementing some auxiliary variables

2. Relate subproblem solutions recursively x(i) = f (x(j), . . .) for one or more j < i

3. Topological order to argue relation is acyclic and subproblems form a DAG

4. Base cases

• State solutions for all (reachable) independent subproblems where relation breaks down

5. Original problem

• Show how to compute solution to original problem from solutions to subproblem(s)


• Possibly use parent pointers to recover actual solution, not just objective function

6. Time analysis
P
• x∈X work(x), or if work(x) = O(W ) for all x ∈ X, then |X| · O(W )
• work(x) measures nonrecursive work in relation; treat recursions as taking O(1) time

1
This property often called optimal substructure. It is a property of recursion, not just dynamic programming
Lecture 15: Recursive Algorithms 5

DAG Shortest Paths


• Recall the DAG SSSP problem: given a DAG G and vertex s, compute δ(s, v) for all v ∈ V

• Subproblems: δ(s, v) for all v ∈ V

• Relation: δ(s, v) = min{δ(s, u) + w(u, v) | u ∈ Adj− (v)} ∪ {∞}

• Topo. order: Topological order of G

• Base cases: δ(s, s) = 0

• Original: All subproblems


P −
• Time: v∈V O(1 + | Adj (v)|) = O(|V | + |E|)

• DAG Relaxation computes the same min values as this dynamic program, just

– step-by-step (if new value < min, update min via edge relaxation), and
– from the perspective of u and Adj+ (u) instead of v and Adj− (v)

Bowling
• Given n pins labeled 0, 1, . . . , n − 1

• Pin i has value vi

• Ball of size similar to pin can hit either

– 1 pin i, in which case we get vi points


– 2 adjacent pins i and i + 1, in which case we get vi · vi+1 points

• Once a pin is hit, it can’t be hit again (removed)

• Problem: Throw zero or more balls to maximize total points

• Example: [ −1, 1 , 1 , 1 , 9, 9 , 3 , −3, −5 , 2, 2 ]


6 Lecture 15: Recursive Algorithms

Bowling Algorithms
• Let’s start with a more familiar divide-and-conquer algorithm:
– Subproblems: B(i, j) = maximum score starting with just pins i, i + 1, . . . , j − 1,
for 0 ≤ i ≤ j ≤ n
– Relation:
∗ m = b(i + j)/2c
∗ Either hit m and m + 1 together, or don’t
∗ B(i, j) = max{vm · vm+1 + B(i, m) + B(m + 2, j), B(i, m + 1) + B(m + 1, j)}
– Topo. order: Increasing j − i
– Base cases: B(i, i) = 0, B(i, i + 1) = max{vi , 0}
– Original: B(0, n)
– Time: T (n) = 4 T (n/2) + O(1) = O(n2 )
• This algorithm works but isn’t very fast, and doesn’t generalize well
(e.g., to allow for a bigger ball that hits three balls at once)

• Dynamic programming algorithm: use suffixes


– Subproblems: B(i) = maximum score starting with just pins i, i + 1, . . . , n − 1,
for 0 ≤ i ≤ n
– Relation:
∗ Locally brute-force what could happen with first pin (original pin i):
skip pin, hit one pin, hit two pins
∗ Reduce to smaller suffix and recurse, either B(i + 1) or B(i + 2)
∗ B(i) = max{B(i + 1), vi + B(i + 1), vi · vi+1 + B(i + 2)}
– Topo. order: Decreasing i (for i = n, n − 1, . . . , 0)
– Base cases: B(n) = B(n + 1) = 0
– Original: B(0)
– Time: (assuming memoization)
∗ Θ(n) subproblems · Θ(1) work in each
∗ Θ(n) total time
• Fast and easy to generalize!
• Equivalent to maximum-weight path in Subproblem DAG:

max{v0 , 0} max{v1 , 0} max{v2 , 0}


B0 B1 B2 B3 ··· Bn

v0 · v1 v1 · v2 v2 · v3
Lecture 15: Recursive Algorithms 7

Bowling Code
• Converting a SRT BOT specification into code is automatic/straightforward
• Here’s the result for the Bowling Dynamic Program above:

1 # recursive solution (top down)


2 def bowl(v):
3 memo = {}
4 def B(i):
5 if i >= len(v): return 0 # base cases
6 if i not in memo: # check memo
7 memo[i] = max(B(i+1), # relation: skip pin i
8 v[i] + B(i+1), # OR bowl pin i separately
9 v[i] * v[i+1] + B(i+2)) # OR bowl pins i and i+1 together
10 return memo[i]
11 return B(0) # original

1 # iterative solution (bottom up)


2 def bowl(v):
3 B = {}
4 B[len(v)] = 0 # base cases
5 B[len(v)+1] = 0
6 for i in reversed(range(len(v))): # topological order
7 B[i] = max(B[i+1], # relation: skip pin i
8 v[i] + B(i+1), # OR bowl pin i separately
9 v[i] * v[i+1] + B(i+2)) # OR bowl pins i and i+1 together
10 return B[0] # original

How to Relate Subproblem Solutions


• The general approach we’re following to define a relation on subproblem solutions:
– Identify a question about a subproblem solution that, if you knew the answer to, would
reduce to “smaller” subproblem(s)
∗ In case of bowling, the question is “how do we bowl the first couple of pins?”
– Then locally brute-force the question by trying all possible answers, and taking the best
∗ In case of bowling, we take the max because the problem asks to maximize
– Alternatively, we can think of correctly guessing the answer to the question, and di-
rectly recursing; but then we actually check all possible guesses, and return the “best”
• The key for efficiency is for the question to have a small (polynomial) number of possible
answers, so brute forcing is not too expensive
• Often (but not always) the nonrecursive work to compute the relation is equal to the number
of answers we’re trying
MIT OpenCourseWare
https://ocw.mit.edu

6.006 Introduction to Algorithms


Spring 2020

For information about citing these materials or our Terms of Use, visit: https://ocw.mit.edu/terms

You might also like