16 Янв в 10:45
11 +1
0
Ответы
1
Коротко — почему неэффективен:
- Рекурсивная функция пересчитывает одни и те же значения много раз (перекрывающиеся подзадачи). Количество вызовов растёт экспоненциально с nnn (приблизительно как числа Фибоначчи). Конкретно число вызовов ~ Fn+1∼ϕn5F_{n+1}\sim\frac{\phi^n}{\sqrt{5}}Fn+1 5 ϕn , где ϕ=1+52\phi=\frac{1+\sqrt{5}}{2}ϕ=21+5 .
- Из-за этого время выполнения экспоненциальное, а для больших nnn практически неосуществимо.
Оценки сложностей:
- Временная сложность (наивный рекурсивный алгоритм): O(ϕn)\displaystyle O(\phi^n)O(ϕn) (часто грубо записывают как O(2n)O(2^n)O(2n)).
- Пространственная сложность (глубина стека рекурсии): O(n)\displaystyle O(n)O(n).
- Примечание: при очень больших nnn надо учитывать стоимость операций с большими целыми: значение FnF_nFn имеет Θ(n)\Theta(n)Θ(n) бит, поэтому примитивные арифметические операции сами по себе становятся дорогими.
Три способа оптимизации (с примерами, преимуществами и ограничениями):
1) Мемоизация (Top‑down DP)
- Идея: запоминать уже вычисленные FkF_kFk и возвращать их вместо повторного вычисления.
- Пример (Python):
def fib_memo(n, memo={}):
if n in memo:
return memo[n]
if n < 2:
memo[n] = n
else:
memo[n] = fib_memo(n-1, memo) + fib_memo(n-2, memo)
return memo[n]
Или кратко: from functools import lru_cache; @lru_cache(None) def fib(n): ...
- Временная сложность: O(n)\displaystyle O(n)O(n) (каждое значение 0..n0..n0..n вычисляется один раз).
- Пространственная: O(n)\displaystyle O(n)O(n) для хранения таблицы + O(n)\displaystyle O(n)O(n) глубина стека (если рекурсивно).
- Преимущества: очень просто внедрить; быстро для средних nnn.
- Ограничения: рекурсивная глубина остаётся O(n)\displaystyle O(n)O(n) (можно переписать итеративно, чтобы убрать стек); память O(n)\displaystyle O(n)O(n).
2) Итеративный (Bottom‑up) с константной памятью
- Идея: вычислять последовательно от 000 до nnn, храня только последние два значения.
- Пример:
def fib_iter(n):
if n < 2:
return n
a, b = 0, 1
for _ in range(n-1):
a, b = b, a + b
return b
- Временная сложность: O(n)\displaystyle O(n)O(n).
- Пространственная сложность: O(1)\displaystyle O(1)O(1) (помимо места для результата).
- Преимущества: простота, нет рекурсии, малое потребление памяти.
- Ограничения: всё ещё линейное время; при очень больших nnn затратны операции с большими целыми.
3) Быстрое возведение в степень / fast doubling (логарифмическое время)
- Идея 1 (матрицы): использовать (1110)n\begin{pmatrix}1&1\\1&0\end{pmatrix}^n(11 10 )n — возведение матрицы за O(log⁡n)\displaystyle O(\log n)O(logn) умножений матриц.
- Идея 2 (fast doubling, формулы):
F2k=Fk(2Fk+1−Fk)F_{2k} = F_k (2F_{k+1} - F_k)F2k =Fk (2Fk+1 Fk ),
F2k+1=Fk+12+Fk2F_{2k+1} = F_{k+1}^2 + F_k^2F2k+1 =Fk+12 +Fk2 .
- Пример (fast doubling):
def fib_fast(n):
def fd(n):
if n == 0:
return (0, 1)
(a, b) = fd(n // 2)
c = a * (2*b - a)
d = a*a + b*b
if n % 2 == 0:
return (c, d)
else:
return (d, c + d)
return fd(n)[0]
- Временная сложность (в терминах арифметических операций): O(log⁡n)\displaystyle O(\log n)O(logn) умножений/сложений больших чисел.
- Пространственная: рекурсивная глубина O(log⁡n)\displaystyle O(\log n)O(logn) (можно сделать итеративно).
- Преимущества: значительно быстрее для очень больших nnn; логарифмическое количество операций.
- Ограничения: операции с большими целыми остаются дорогими — учитывая размер чисел (они имеют Θ(n)\Theta(n)Θ(n) бит), стоимость умножений/сложений нужно учитывать в оценке по битовым операциям; для экстремально больших nnn нужны оптимизации арифметики (FFT‑умножение) или вычисление по модулю.
Краткое резюме:
- Наивный рекурсивный алгоритм экспоненциален: O(ϕn)\displaystyle O(\phi^n)O(ϕn), глубина стека O(n)\displaystyle O(n)O(n).
- Простые и эффективные улучшения: мемоизация (O(n) время, O(n) память), итеративный счёт (O(n) время, O(1) память), fast doubling / матрицы (O(\log n) операций — лучшая по времени при больших nnn). Выбор зависит от nnn и ограничений по памяти / точности / арифметике.
16 Янв в 11:30
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир