- Recurrences
- Dynamic Programming
- bottom-up approach
- memoization (top-down approach)

- Bottom-up DP VS memoization

- A
*recurrence*is a way to define a function on the (tuples of) nonnegative integers by giving two things:- values of the function for a finite number of base cases
- values of the function for the rest of the cases in terms of values of the function on “smaller arguments”

- Example 1: The Fibonacci numbers \(f(n)\) are defined as \[ f(n) = \left\{ \begin{array}{ll} n, & \mbox{if $n=0$ or $n=1$} \\ f(n-1) + f(n-2), & \mbox{if $n \ge 2$} \end{array} \right. \]
- Example 2: The Bionomial Coefficients \(C(n, k)\) are defined for all \(n\ge 0\) and all \(0\le k\le n\) as \[ C(n,k) = \left\{ \begin{array}{ll} 1, & \mbox{if $k=0$ or $k=n$} \\ C(n-1,k) + C(n-1,k-1), & \mbox{otherwise} \end{array} \right. \]

- Suppose a function is defined via a recurrence, and we want to write a program to evaluate the function when given its argument(s).
- As demonstrated in class, some program, if naively translated from the recurrence, is inefficient due to heavily repeated computation.
**Note.**We can use the techniques of this slide to solve more problems than just function evaluation. E.g., we’ll demonstrate how to solve the Longest Common Subsequence problem in class.

- Bottom-up dynamic programming is appropriate for solving a problem that can be described by a recurrence.
- It is a bottom-up approach.

- Use a table to store computed values.
- We solve all problems on all smaller sizes by performing the following two steps.
- Fill in all entries of the table
*bottom-up*using the recurrence. - Return the desired value from the desired table entry.

- Fill in all entries of the table

- Like bottom-up DP, it is a programming technique for evaluating a recursively-defined function efficiently.
- It works by modifying the naive translation of recurrence.
- It is a top-down approach.

- Use a table to store previously computed values.
- Initialize the whole table to
*UNKNOWN VALUE*except entries of the base cases, where we put in their correct values. - Each time a value is computed and known, immediately store it into the table.
- Any time a value is needed, check first whether it is already stored in the table. If it is, use it; otherwise, compute its value.
- To compute the value of the function on any argument, use the recurrence and the above two ideas.

Memoization | Bottom-up DP | |
---|---|---|

Implementation of recurrence |
top-down | bottom-up |

Initialization of table |
required | not required |

# table entries computed |
partial | complete |

Space-saving improvement |
not possible | possible |