# fibonacci variants
# NOTICE: you may NOT use the automated memoization in this
# file for Assignment 3

def fibonacci(n: int) -> int:
    """nth fibonacci number, where fibonacci(0) is 0 and fibonacci(1) is 1,
    and fibonacci(n) = fibonacci(n-1) + fibonacci(n-2) if n > 1

    >>> fibonacci(5)
    5
    >>> fibonacci(6)
    8
    """
    return n if n < 2 else fibonacci(n - 1) + fibonacci(n - 2)


def fibonacci_mem(n: int) -> int:
    """memoized fibonacci"""
    cached = {}
    def fib_rec(n: int) -> int:
        if not n in cached:
            if n < 2:
                cached[n] = n
            else:
                cached[n] = fib_rec(n - 1) + fib_rec(n - 2)
        return cached[n]
    return fib_rec(n)


def memoize(f: 'function') -> 'function':
    """Return memoized version of f"""
    table = {}
    def g(x):
        if not x in table:
            table[x] = f(x)
        else:
            pass
        return table[x]
    return g

# fibonacci = memoize(fibonacci)
