以下の関数を考えます:
_int f(int n) {
if (n <= 1) {
return 1;
}
return f(n - 1) + f(n - 1);
}
_
Big Oの時間の複雑さはO(2^N)
であることを知っています。これは、各呼び出しが関数を2回呼び出すためです。
私が理解していないのは、スペース/メモリの複雑さがO(N)
なのはなぜですか?
これらのタイプの問題にアプローチする便利な方法は、 再帰ツリー を考えることです。識別する再帰関数の2つの機能は次のとおりです。
この場合の再帰関係はT(n) = 2T(n-1)
です。 O(2^n)
の場合は時間の複雑さを正しく指摘しましたが、繰り返しツリーに関連して見てみましょう。
_ C
/ \
/ \
T(n-1) T(n-1)
C
____/ \____
/ \
C C
/ \ / \
/ \ / \
T(n-2) T(n-2) T(n-2) T(n-2)
_
このパターンは、 like this に見えるベースケースまで続きます。
連続するツリーレベルごとに、nは1ずつ減少します。したがって、ツリーはベースケースに到達する前にの深さnを持ちます。各ノードには2つのブランチがあり、合計レベルはnなので、ノードの合計数は_2^n
_であり、時間の複雑さはO(2^n)
です。
各関数呼び出しはプログラムスタックに格納されるため、メモリの複雑さはreturnステートメントの数によって決まります。一般化すると、再帰関数のメモリの複雑さはO(recursion depth)
です。ツリーの深さが示唆するように、合計returnステートメントがn個あるため、メモリの複雑さはO(n)
です。