1つの記事は時間の複雑さと空間の複雑さを理解しています

データ構造とアルゴリズムを学習するための最初のステップ

時間の複雑さ

最も一般的な時間計算量は何ですか

  • O(1):一定の複雑さ
  • O(log n):対数ComPlexity対数の複雑さ
  • O(n):線形ComPlexity線形時間計算量
  • O(n ^ 2):N平方ComPlexity平方
  • O(n ^ 3):Nキュービック複雑さ
  • O(2 ^ n):指数関数的成長指数
  • O(n!):階乗階乗

時間計算量を分析する場合、フロント係数は考慮されません。たとえば、O(1)は、その複雑さが1であることを意味しません。一定の次数である限り、2、3、4 ...にすることもできます。 O(1)は

コードの時間計算量を確認するにはどうすればよいですか?

最も一般的な方法は、このコードを直接確認することです。nのさまざまな状況に応じて実行される回数です。

O(1)
$n=100000;
echo 'hello';

O(?)
$n=100000;
echo 'hello1';
echo 'hello2';
echo 'hello3';

nが何であれ、最初のコードは1回だけ実行されるため、時間計算量はO(1)です。2つ目は実際には同じで、係数は関係ありません。2番目のコードはエコー出力を3回実行しますが、nが何であっても3回しか実行されないため、時間計算量も一定の複雑さ、つまりO(1)です。

次の2つのコードを見てください。

O(n)
for($i = 1; $i <= $n; $i++) {
    echo 'hello';
}

O(n^2)
for($i = 1; $i <= $n; $i++) {
    for($j = 1; $j <= $n; $j++) {
        echo 'hello';
    }
}

これら2つのコードはどちらもnで異なり、実行回数も変化しています。最初のコードの実行回数はnに比例するため、時間計算量はO(n)です。

2番目のコードはネストされたループです。nが100の場合、内部の出力ステートメントは10,000回実行されるため、時間計算量はO(n ^ 2)です。2番目のコードのループがネストされていないが並列である場合、その時間計算量はO(2n)である必要があります。これは、フロントの定数係数を気にしないため、時間計算量はO(n)です。

O(log n)
for($i = 1; $i <= $n; $i = $i*2) {
    echo 'hello';
}

O(k^2)

fib($n) {
    if ($n < 2) {
        return $n;
    }
    
    return fib($n-1) + fib($n-2);
}

最初のコードでは、n = 4の場合、ループは2回実行されるため、ループ内の実行数とnの関係はlog2(n)であるため、時間計算量は対数計算量O(logn)になります。2番目の段落はフィボナッチ(フィボナッチ)シーケンスです。ここでは、この形式の再帰を使用します。これには、再帰プログラムの実行時の時間計算量の計算方法が含まれます。その答えはk ^ nで、Kは定数で指数関数です。そのため、フィボナッチ数列を単純に再帰的に見つけるのは非常に遅く、これは指数関数的な時間計算量です。特定の指数時間計算量がどのように得られるかについては、後で詳しく説明します。さまざまな時間計算量の曲線を見てみましょう

この図から、nが比較的小さい場合(10以内)、異なる時間計算量は実際には類似していることがわかります。しかし、nが拡大し続けると、指数関数的成長は非常に速くなります。したがって、プログラムを作成するときに、たとえば2nからn2までの時間計算量を最適化できれば、この曲線の観点から、nが大きいと、得られるメリットは非常に高くなります。したがって、ビジネスコードを開発するときは、自分の時間と空間の複雑さを理解する必要があり、習慣を身に付けるのが習慣であることもわかります。コードを記述した後、このプログラムの時間と空間を無意識のうちに分析します。複雑さ。

図からわかるように、時間計算量を壊すと、nが増えるにつれて会社のマシンまたはリソースの損失が実際に増加し、単純化できれば、会社のコストを大幅に節約できます。

プログラムが異なれば、書き込み方法で同じ目標を達成すると、時間の複雑さが異なる可能性があります。簡単な例を見てみましょう

从1加到2一直加到n,求它的和

小学校で数学を学ぶとき、誰もが2つの方法があることを知っていました。方法1では、プログラムを使用して暴力でそれを解決する場合、1からnの累積にループします。これは1レベルのループです。nの回数だけ累積が実行されるため、時間計算量はO(n)です。

$sum = 0;
for ($i=1; $i <=$n; $i++) {
    $sum += $i;
}

方法2は、数学的な合計式を使用することです。

y = n*(n+1)/2

この式を使用すると、プログラムには1行しかないため、時間計算量はO(1)であることがわかります。したがって、プログラムのさまざまな方法で得られる最終結果は同じですが、時間計算量が大きく異なることがわかります。

再帰の場合、時間計算量を分析する方法は?

再帰の場合、重要なのは、その再帰プロセス、つまり合計でいくつの再帰ステートメントが実行されるかを理解することです。ループの場合、n回のループがn回実行されていることがわかります。再帰の場合、実際にはレイヤーごとにネストされており、実際、再帰の実行順序に基づいてツリー構造を描画し、再帰状態の再帰ツリーと呼んでいます。フィボナッチ数列のn番目の項を見つける前の例を見てください

Fib:0,1,1,2,3,5,8,13,21...

F(n) = F(n-1)+F(n-2)

以前のインタビューでそのような質問に遭遇しましたが、再帰的にそれを達成するための最も簡単な方法でそれを書きました。

fib($n) {
    if($n < 2) {
        retuen $n;
    }
    
    return fib($n-1)+fib($n-2);
} 

時間計算量はO(k ^ n)であると前述したので、それを取得する方法は、nが6であると仮定して、Fib(6)を計算するために分析できます。これは、このコードの実行方法によって異なります。

したがって、F(6)を計算する場合は、F(5)とF(4)の2つの分岐があり、少なくともさらに2つの演算があります。

F(5)を計算したい場合は、同じ方法で取得できます。F(4)とF(3)を決済する必要があります。F(4)を計算したい場合は、同じ方法で取得できます。F(3)とF(2)を決済する必要があります。ここでは2つの現象が見られます。

  • 追加のレイヤーごとに、実行中のノードの数は上位レイヤーの2倍になります。最初のレイヤーには1つのノード、2番目のレイヤーには2つのノード、3番目のレイヤーには4つのノード、次のレイヤーには8つのノードがあります。したがって、各レイヤーについて、ノードの数、つまり実行の数は指数関数的に増加します。nに達すると、2 ^ n回実行されたことがわかります。
  • 2つ目は、図のF(4)やF(3)のように、実行ツリーに重複ノードが表示されていることを確認できますこのツリーを展開し続けると、F(4)、F(3)、F(2)が何度も計算されることがわかります。

冗長な計算が非常に多いため、6個のフィボナッチ数が2 ^ 6の時間計算量になるからです。したがって、面接でこの種の質問に遭遇したときは、このように書かないようにしてください。そうしないと、寒くなります。これらの中間結果をキャッシュするためにキャッシュを追加するか(配列またはハッシュに保存し、繰り返し計算される値を見つける)、またはループに直接書き込むことができます

主定理

主定理と呼ばれるものを導入します。この定理が重要である理由は、主定理が実際にすべての再帰関数を解くために使用され、その時間計算量を計算する方法だからです。主定理自体は数学的に証明するのが比較的複雑です(主定理については、ウィキペディアを参照してください:https://zh.wikipedia.org/wiki/%E4%B8%BB%E5%AE%9A%E7%90% 86)

言い換えれば、分割統治法または再帰関数は、その時間計算量を計算でき、その計算方法はこの主要な定理によって行われます。それがもっと複​​雑な場合、それを実用的な方法に単純化する方法、実際、鍵はこれらの4つです、一般的に覚えておいてください

一般に、さまざまな再帰的な状況では、面接や通常の作業で使用される上記の4つの状況があります。

二分探索:通常、数字のシーケンスが順番に並んでいて、ターゲットの数字が数字のシーケンスで見つかった場合に発生するため、毎回2つに分割され、片側のみがチェックされます。この場合、最後の時間複雑さはO(logn)です

二分木トラバーサル二分木トラバーサルの場合、その時間計算量はO(n)です。主定理から、毎回2つに分割されていることがわかりますが、2つに分割された後は、それぞれの側で同じ時間計算量になります。最後に、その漸化式は、図ではT(n)= 2T(n / 2)+ O(1)になります。最後に、この主な定理によれば、その実行時間はO(n)であると結論付けることができます。もちろん、単純化された考え方もあります。つまり、バイナリツリーをトラバースすると、各ノードは1回だけアクセスされるため、時間計算量はO(n)になります。

2次元行列(最適な並べ替え行列検索):2次元検索は、並べ替えられた2次元行列で実行されます。現時点では、時間計算量は主定理によりO(n)です。覚えておいてください。

マージソート(マージソート):すべてのソートに最適な方法はnlognであり、マージソートの時間計算量はO(nlogn)です。

時間計算量に関する一般的な面接の質問

二分木のトラバーサル-プレオーダー、ミドルオーダー、ポストオーダー:時間計算量とは何ですか?

答えは次のとおりです。O(n)、ここでnはバイナリツリー内のノードの総数を表します。トラバースする方法に関係なく、各ノードは1回しかアクセスしないため、その複雑さは、のノードの総数に比例します。二分木。これはO(n)です。

グラフ走査:時間計算量とは何ですか?

回答:O(n)、グラフ内の各ノードにも1回だけアクセスされるため、時間計算量もO(n)、nはグラフ内のノードの総数です。

検索アルゴリズム:DF​​S(深さ優先)とBFS(幅優先)の時間計算量はどれくらいですか?

回答:O(n)、次の記事では、これら2つのアルゴリズムを詳細に紹介します(nは検索空間内のノードの総数です)

二分探索:時間計算量とは何ですか?

回答:O(logn)

スペースの複雑さ

空間の複雑さと時間の複雑さの状況は似ていますが、より単純です。最も簡単な方法で分析します。2つの主要な原則があります:

コードで配列を開く場合、配列の長さは基本的にスペースの複雑さです。あなたは一次元配列を開いた場合、その後、あなたのスペースの複雑さはO(n)がある。あなたは2次元配列を開き、配列の長さがnの場合は2、そして宇宙の複雑さがn基本的に2

再帰がある場合、再帰の最も深い深さは、スペースの複雑さの最大値です。プログラムで再帰的に配列を開くと、スペースの複雑さは2つのうち最大のものになります。

急速に変化するテクノロジーの常識を見つけることは、技術者のコアコンピタンスです。理論と実践を組み合わせた知識と行動の統一

おすすめ

転載: blog.csdn.net/self_realian/article/details/107531012