数の階乗n
を見つけるための再帰プログラムの複雑さは何ですか?私の勘は、それがO(n)
かもしれないということです。
乗算をO(1)
として取る場合、はい、O(N)
が正しいです。ただし、任意の長さの2つの数値を乗算すると、x
はnotO(1)
であり、有限ハードウェアではx
が無限大になる傾向があるため、乗算に必要な時間が長くなります(例: Karatsuba multiplication を使用する場合、O(x ** 1.585)
)。
理論的には Schönhage-Strassen を使用して十分に大きな数を処理することができますが、実際の経験はありません。 x
、「長さ」または「桁数」(どのようなベースでも、Nのbig-Oには関係ありません。もちろん、O(log N)
で大きくなります。
O(1)
で乗算するのに十分短い数の階乗に質問を限定するつもりなら、N
が「無限大になる」可能性がないため、big-O表記は不適切です。
アルゴリズムの複雑さを表現するとき、それは常に入力サイズの関数として存在します。乗算する数値のサイズが固定されている場合、乗算がO(1)
演算であると想定することのみが有効です。たとえば、行列の積を計算するアルゴリズムの複雑さを判断する場合、行列の個々のコンポーネントのサイズが固定されていると想定することができます。次に、2つの個別のマトリックスコンポーネントの乗算がO(1)
であると想定することは有効であり、各マトリックスのエントリ数に従って複雑さを計算します。
ただし、_N!
_を計算するアルゴリズムの複雑さを理解する場合は、N
が任意に大きくなる可能性があると想定する必要があるため、乗算がO(1)
操作。
Nビットの数値とmビットの数値を乗算したい場合、単純なアルゴリズム(手動で行うようなもの)は時間がかかりますO(mn)
ですが、より高速なアルゴリズムがあります。
_N!
_を計算するための簡単なアルゴリズムの複雑さを分析したい場合
_ factorial(N)
f=1
for i = 2 to N
f=f*i
return f
_
次に、forループのk番目のステップで、_(k-1)!
_にk
を乗算します。 _(k-1)!
_を表すために使用されるビット数はO(k log k)
であり、k
を表すために使用されるビット数はO(log k)
です。したがって、_(k-1)!
_とk
を乗算するのに必要な時間はO(k (log k)^2)
です(単純な乗算アルゴリズムを使用している場合)。次に、アルゴリズムにかかる合計時間は、各ステップでかかる時間の合計です。
sum k = 1 to N [k (log k)^2] <= (log N)^2 * (sum k = 1 to N [k]) =
O(N^2 (log N)^2)
このパフォーマンスを向上させるには、2 nビットの数値に対してO(n*log(n)*log(log(n)))
の時間がかかるSchönhage-Strassenのような、より高速な乗算アルゴリズムを使用します。
パフォーマンスを改善するもう1つの方法は、より良いアルゴリズムを使用して_N!
_を計算することです。私が知っている最も速いものは、最初に_N!
_の素因数分解を計算し、次にすべての素因数を乗算します。
これまでで最も単純な階乗アルゴリズムについて話していると仮定します。
factorial (n):
if (n = 0) then return 1
otherwise return n * factorial(n-1)
はい、アルゴリズムは線形で、O(n)時間で実行されます。これは、値n
をデクリメントするたびに1回実行され、値をデクリメントするためですn
は、関数が0
に到達するまで、つまり関数がn
回再帰的に呼び出されることを意味します。これは、もちろん、減分と乗算の両方が定数演算であることを前提としています。
もちろん、他の方法で階乗を実装する場合(たとえば、乗算の代わりに再帰的に加算を使用する場合)は、はるかに複雑なアルゴリズムになる可能性があります。ただし、このようなアルゴリズムを使用することはお勧めしません。
再帰的な階乗の時間の複雑さは次のようになります。
factorial (n) {
if (n = 0)
return 1
else
return n * factorial(n-1)
}
そう、
1つの再帰呼び出しの時間の複雑さは次のようになります。
T(n) = T(n-1) + 3 (3 is for As we have to do three constant operations like
multiplication,subtraction and checking the value of n in each recursive
call)
= T(n-2) + 6 (Second recursive call)
= T(n-3) + 9 (Third recursive call)
.
.
.
.
= T(n-k) + 3k
till, k = n
Then,
= T(n-n) + 3n
= T(0) + 3n
= 1 + 3n
Big-Oh表記で表すには、
T(N)はnに正比例し、
したがって、再帰的階乗の時間の複雑さはO(n)です。再帰呼び出し中に余分なスペースが取られないため、スペースの複雑さはO(N)です。