Search code examples
pythonrecursionfibonaccimemoization

How to make a recursive fib-function return the correct value with memoization


I'm learning about memoization in recursive functions and stumbled upon a fibonacci-example on Youtube. I never saw the person run the code so perhaps he wrote it wrong.

When I copied the code and tried to run it, i first got an error since I declared memo without a range, so I simply set the range to the input + 1 (since I'm not using the 0-index) and thus solved that problem. But now I'm stuck at the wrong return value.

def fib(num, memo=[]):
    if num == 0:
        return 0
    elif num == 1 or num == 2:
        return 1
    elif memo[num] != None:
        return memo[num]
    else:
        memo[num] = fib(num-1, memo) + fib(num-2, memo)
        return memo[num]

uInput = int(input("Fibonacci: "))
memo = list(range(uInput + 1))
fibNum = fib(uInput, memo)

print(fibNum)

The code above throws no error but simply returns the "uInput" value. So if I input 6, for the 6st fibonacci number, the program returns 6 instead of 8, which is the actual 6st number. I am at a loss as to why this occurs.

When I have googled the issue I have found threads that suggested using dicts instead of lists. Thats all fine if that is the only way to do it. But if there is a way to make it work with a list I would like to understand how that is done so that I understand why I run in to this problem.


Solution

  • Accessing memo[num] will never return None. If num is out of range, a IndexError will be raised. Moreover, you typically do not want to pass a memo argument to your function and instead let it rely on its own memo object.

    In your case, you want to check that the index is in range with len. Whenever num is out of range, the output must be computed recursively and memoized. Only then can it be returned.

    def fib(num, memo=[0, 1]):
        if num >= len(memo):
            memo.append(fib(num - 1) +  fib(num - 2))
        return memo[num]
    
    print(fib(10)) # 55
    

    By the way, the above can easily be transformed into an iterative function which is typically more efficient in Python.

    def fib(num, memo=[0, 1]):
        while num >= len(memo):
            memo.append(memo[-1] + memo[-2])
        return memo[num]