Разберите код на Python с рекурсией и мемоизацией для вычисления чисел Фибоначчи; оцените по времени и памяти и предложите улучшения

21 Ноя в 10:36
4 +1
0
Ответы
1
Пример типичного кода с рекурсией и мемоизацией (две реализации):
1) С помощью lru_cache:
```python
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
```
2) С помощью словаря:
```python
def fib(n, memo={}):
if n < 2:
return n
if n in memo:
return memo[n]
memo[n] = fib(n-1, memo) + fib(n-2, memo)
return memo[n]
```
Анализ по времени и по памяти
- Количество уникальных вычислений: каждый индекс 0..n0..n0..n вычисляется не более одного раза, значит число вызовов/сложений — O(n)O(n)O(n). В терминах сложностной нотации: время по числу операций сложения/доступов — O(n)O(n)O(n).
- Однако числа Фибоначчи растут экспоненциально, их битовая длина примерно
∼nlog⁡2φ\sim n\log_2\varphinlog2 φ, где φ=(1+5)/2\varphi=(1+\sqrt5)/2φ=(1+5 )/2. Поэтому стоимость одной операции сложения/умножения зависит от размера чисел. В битовой модели:
- сложение O(n)O(n)O(n) бит,
- умножение O(M(n))O(M(n))O(M(n)) бит (где M(n)M(n)M(n) — стоимость умножения n-битных чисел).
Тогда общая битовая сложность рекурсивной мемоизированной реализации примерно O(n2)O(n^2)O(n2) при использовании наивного сложения/учёта роста длин (точнее, сумма размеров хранимых чисел даёт O(n2)O(n^2)O(n2) битовых операций).
- Память (RAM):
- количество хранимых значений в memo — O(n)O(n)O(n) объектов (каждое — целое число),
- глубина рекурсии — O(n)O(n)O(n) (стек вызовов),
- в битах суммарный объём для всех сохранённых чисел ~ сумма битовых длин =O(n2)=O(n^2)=O(n2) бит.
Итого: по объектам/записям — O(n)O(n)O(n), по битам/байтам — O(n2)O(n^2)O(n2) из‑за роста размеров чисел.
Практические проблемы данной реализации
- Рекурсия в Python: стек ограничен (обычно ~1000), для больших nnn будет RecursionError.
- Кеш (lru_cache или dict) хранит все вычисленные значения, что может потреблять много памяти для больших nnn.
- Для очень больших nnn время ограничено не количеством операций, а стоимостью операций на больших целых числах.
Предложения по улучшению
1) Итеративная версия с O(1) дополнительной памяти и без рекурсии (рекомендуется для большинства задач):
```python
def fib_iter(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
```
- Время по операциям: O(n)O(n)O(n).
- Память: O(1)O(1)O(1) целых (но сами целые растут по битам).
2) Быстрое удвоение (fast doubling) — асимптотически быстрее по числу арифметических операций, рекурсия глубиной O(log⁡n)O(\log n)O(logn):
```python
def fib_fast_doubling(n):
def fd(k):
if k == 0:
return (0, 1)
a, b = fd(k >> 1)
c = a * (2*b - a)
d = a*a + b*b
if k & 1:
return (d, c + d)
else:
return (c, d)
return fd(n)[0]
```
- Количество больших умножений/сложений ~ O(log⁡n)O(\log n)O(logn).
- Битовая сложность примерно O(M(n)log⁡n)O(M(n)\log n)O(M(n)logn) (где M(n)M(n)M(n) — стоимость умножения n-битных чисел). При наивном умножении M(n)=O(n2)M(n)=O(n^2)M(n)=O(n2), с улучшенными алгоритмами умножения сложность снижается.
3) Для единственного большого nnn — использовать fast doubling или матричное возведение в степень (экспоненциация по модулю или для целых с быстрым умножением). Для множества запросов с разными nnn — выгодно кэшировать результаты (но контролировать размер кеша).
4) Практические замечания:
- Избегайте рекурсии для n≳1000n\gtrsim 1000n1000 в Python (ошибки стека).
- Если память ограничена, используйте итеративный вариант с двумя переменными.
- Для очень больших nnn (много сотен тысяч цифр) используйте fast doubling и полагайтесь на оптимизации умножения больших целых в интерпретаторе (CPython использует разные алгоритмы, включая FFT для очень больших чисел).
Короткая рекомендация:
- Нужна простота и nnn не очень велико → итеративный цикл.
- Нужен самый быстрый асимптотический алгоритм для огромного nnn → fast doubling (или специализированные библиотеки для больших чисел).
21 Ноя в 10:43
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир