web-dev-qa-db-ja.com

再帰を使用する次のプログラムの時間の複雑さを見つける

与えられた数の階乗を計算する次のプログラムのBig Oh表記で時間の複雑さを見つける必要があります。プログラムは次のようになります。

public int fact(int n){

  if (n <=1)
    return 1;
  else
  return n * fact (n-1);
}

上記のプログラムは再帰を使用していますが、上記のプログラムの時間の複雑さをどのように導出するのですか?

2
Pradeep

このソリューションは、はるかに簡単に簡単に変換できます。

_int res = 1;
for(int i = 1; i <= n; ++i) {
    res *= i;
}
_

乗算がO(1)であることを考えると( カラツバ乗算 を使用している場合、O(m^1.585)であり、mは数値の長さです)結果は次のようになります。この関数のO(n)

6
m0nhawk

さて、乗算がかかると仮定しましょう O(n^1.585) m0nhawkが示唆する時間。

O_m_1.585_m_log_10_n_log_10_n_1.585.gif

再帰的な時間方程式を定義する必要があります。

Recursive time equation: T(n) = \left{\begin{array}{ll} \mathcal{O}(1) & n = 1 \ \mathcal{O}({\log_{10}(n)}^{1.585}) + T(n-1) & \text{else} \end{array} \right.

この方程式を解くと、次の結果が得られます。

Sum

これは基本的に:

k\cdot\mathcal{O}\left({\log_{10}(n)}^{1.585}\right) + \mathcal{O}(1)

ここで、kはn-1であるため、次のようになります。

\mathcal{O}\left(n\cdot{\log(n)}^{1.585}\right)

ただし、乗算に一定の時間がかかると仮定した場合、O(n)は正しい実行時の近似値です。

4
meisterluk

古い質問を復活させて申し訳ありませんが、ここで何度も繰り返される間違いがあるのではないかと思います。

私の知る限り、計算の複雑さは、入力(n)の効率的なエンコーディングのサイズで定義されています。

階乗の入力値mが与えられた場合、アルゴリズムがm乗算を必要とすることは事実です。ただし、数値mの効率的なエンコードはサイズn := log mであるため、これは線形順序ではありません(つまり、エンコードされた入力のサイズと同じ順序です)。

これは、入力の(効率的なエンコード)サイズでの時間の複雑さは確かにIS指数(m = 2^n乗算)であることを意味します!

m乗算は、入力の単項エンコーディングを選択した場合にのみ、入力で線形になります。これは、「効率的な」選択ではありません。

「効率的なエンコーディング」について

ユーザーSSHが尋ねたので、「効率的なエンコーディング」の概念について少し詳しく説明しましょう。

それを理解する鍵は、アルゴリズムの漸近的な複雑性が「計算時間の増加の速さ、つまり入力の増加の速さ」という観点から定義されていることを理解することです。

通常、入力のサイズは直感的です。nアイテムのリストにはsize nがあります。しかし、このスレッドが焦点を当てている例のように、それは時々あなたをつまずかせることがあります。これが、計算の複雑さの定義に「効率的なエンコーディング」と明示的に示されている理由です。2つの考えられる間違いを防ぐためです。

1:有限のアルファベットを使用して入力をエンコードする必要があることを忘れる

factorialの例では、入力サイズがnotであると誤解している可能性があります。常に「1つの番号」を扱います。これは有効ではありません。チューリングマシンに「数値」を送るのは意味がないためです(無限のサイズのアルファベットが必要です)。有限のアルファベットを使用して数値をエンコードする必要があります。数値のこの表現は、数値nが大きくなると大きくなります。

2:非効率なエンコーディングを選択する

計算の複雑さはエンコードされた入力サイズに対して相対的に定義されるため、非常に効率の悪いエンコードを選択することで複雑さを操作できます。

例:マシン入力テープのn^2トークンを使用してnアイテムのリストを非常に非効率的にエンコードするとします。サイズnのリストにn^2計算ステップを使用するすべてのアルゴリズムが、エンコードされた入力サイズでlinearになりました!それは当然のことではありません。したがって、分析を成功させるには、エンコーディングが効率的でなければなりません。

別の例としては、直感を聞いて、4は2の2倍のサイズであると考えています。2ビットを使用して2を、3ビットのみを使用して4を効率的にエンコードできるため、これは当てはまりません。

潜在的な落とし穴:エンコードされた入力サイズの絶対値との比較。

絶対サイズ関心がないが、エンコードされた入力の成長率に関心があることを覚えておいてください。2つのリスト* n整数は、n項目のリストのサイズの2倍です。

2
A.J.Rouvoet

反復方程式:

_           | e                if n = 1
T(n) =     |
           | T(n - 1) + d     if n > 1

f(n) = d so is a 0-degree polynomial, n^0

T(n) ∈ Θ(n^0+1) = Θ(n)
_

チップと征服の方法

サイズnの問題は、サイズn-cの1つのサブ問題に細分されます。

_T(n) = T(n - c) + f(n)
_

_c > 0_(チッピングファクター)およびf(n)が非再帰的なコストである場合(サブ問題を作成するため、および/または他のサブ問題のソリューションと組み合わせるため))T(n)は、次のように漸近的に制限できます。

  • f(n)が多項式_n^α_の場合、T(n) ∈ Θ(n^(α+1))
  • f(n)が_lg n_の場合、T(n) ∈ Θ(n lg n)
1
Nishant