← Все вопросы
Почему рекурсивный Фибоначчи такой медленный и как его ускорить через lru_cache?
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.
Ваш ответ
Войдите, чтобы ответить на вопрос.