Section 7 / 13
再帰のメモ化による最適化
再帰は、多くのアルゴリズムにおいて自然で直感的なアプローチを提供しますが、特に重複する計算を行う場合には非効率的です。メモ化は、計算結果を保存して再利用することで、再帰的なアルゴリズムのパフォーマンスを大幅に向上させるテクニックです。この教材では、再帰のメモ化を使用して、フィボナッチ数列の計算を最適化する方法を学びます。
メモ化の基本概念
メモ化は、関数の引数に対する戻り値をキャッシュすることで、同じ入力に対する計算を繰り返さないようにします。これにより、特に再帰的な関数において、計算時間が大幅に短縮されます。
フィボナッチ数列の再帰的定義
フィボナッチ数列は、次のように定義されます: - F(0) = 0 - F(1) = 1 - F(n) = F(n-1) + F(n-2) (n >= 2)
この定義を用いると、フィボナッチ数列を計算する再帰関数を簡単に実装できます。
再帰によるフィボナッチ数列の実装
まず、メモ化を使わない再帰的なフィボナッチ数列の実装を見てみましょう。
def fibonacci(n):
if n <= 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
# サンプル実行
print(fibonacci(10)) # 出力: 55
コードの解説
- 関数
fibonacciは、引数nに対してフィボナッチ数を計算します。 - 基本ケースとして、
nが 0 または 1 の場合に直接結果を返します。 - それ以外の場合は、再帰的に
fibonacci(n - 1)とfibonacci(n - 2)を呼び出します。
この実装は分かりやすいですが、計算量は指数関数的であり、特に大きな n に対しては非常に遅くなります。
メモ化による最適化
次に、メモ化を使ってこの関数を最適化します。Pythonでは、functools モジュールの lru_cache デコレーターを使うことで、簡単にメモ化を実装できます。
from functools import lru_cache
@lru_cache(maxsize=None) # 無限キャッシュサイズ
def fibonacci_memo(n):
if n <= 0:
return 0
elif n == 1:
return 1
else:
return fibonacci_memo(n - 1) + fibonacci_memo(n - 2)
# サンプル実行
print(fibonacci_memo(10)) # 出力: 55
コードの解説
functools.lru_cacheデコレーターを使って、関数fibonacci_memoにメモ化機能を追加します。- このデコレーターは、関数が呼び出されるときに引数と戻り値をキャッシュし、同じ引数で呼び出された際にキャッシュから結果を返します。
- キャッシュサイズは
maxsizeパラメータで指定できますが、Noneを設定することで無限にキャッシュを持つことができます。
この変更により、計算量は線形時間に改善され、非常に大きな n に対しても効率的にフィボナッチ数を計算できるようになります。
まとめ
メモ化は、再帰的なアルゴリズムのパフォーマンスを劇的に向上させる強力な手法です。この教材では、フィボナッチ数列を例にして、メモ化の基本的な概念と実装方法を学びました。再帰を用いた問題に直面した場合は、ぜひメモ化を考慮してみてください。