← Все вопросы

Почему рекурсивный Фибоначчи такой медленный и как его ускорить через lru_cache?

Задан 9 месяцев назад669 просмотров3 ответа
12

Наивная рекурсия Фибоначчи на fib(40) уже думает несколько секунд, а на fib(45) вообще зависает:

def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

Почему так медленно и как починить, не переписывая всё на цикл?

3 ответа

22
✓ Принятый ответ — помог автору

Беда в том, что одни и те же значения пересчитываются заново миллионы раз: fib(5) зовёт fib(4) и fib(3), fib(4) снова зовёт fib(3) и так далее. Сложность экспоненциальная — примерно O(2^n).

Самый простой фикс — кешировать результаты декоратором:

from functools import lru_cache

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

fib(45)  # мгновенно

Теперь каждое fib(n) считается один раз и берётся из кеша при повторе — сложность падает до O(n). Код почти не меняется, добавилась одна строка. Аргументы должны быть хешируемыми (числа подходят).

Елена Костюченко На больших n не забудь про лимит глубины рекурсии — может прилететь RecursionError · 9 месяцев назад
Сергей Галанов В 3.9+ есть ещё короче — @cache из functools, то же что lru_cache(maxsize=None) · 9 месяцев назад
7

Потому что одни и те же fib(k) считаются по много раз (экспонента). Навесь @lru_cache(maxsize=None) из functools — станет O(n).

3

@lru_cache.

Ваш ответ

Войдите, чтобы ответить на вопрос.
Поддержать проект