この以前の質問は、アルゴリズムにO(log n)の複雑さを引き起こす可能性のあるいくつかの要因に対処しています。
アルゴリズムが時間の複雑さO(log log n)を持つ原因は何ですか?
この以前の質問は、アルゴリズムにO(log n)の複雑さを引き起こす可能性のあるいくつかの要因に対処しています。
アルゴリズムが時間の複雑さO(log log n)を持つ原因は何ですか?
回答:
O(log log n)の用語はさまざまな場所で表示されますが、通常、このランタイムに到達する2つの主要ルートがあります。
リンクされた質問への回答で述べたように、アルゴリズムが時間の複雑さO(log n)を持つ一般的な方法は、そのアルゴリズムが各反復で定数の係数によって入力のサイズを繰り返し削減することによって機能することです。これが当てはまる場合、アルゴリズムはO(log n)の反復後に終了する必要があります。定数でO(log n)を除算した後、アルゴリズムは問題のサイズを0または1に縮小する必要があるためです。これが理由です。 、二分探索は複雑度O(log n)を持ちます。
興味深いことに、O(log log n)の形式のランタイムを生成する問題のサイズを縮小する同様の方法があります。各レイヤーで入力を半分に分割する代わりに、各レイヤーでサイズの平方根を取得するとどうなりますか?
たとえば、65,536という数字を考えてみましょう。これを2で除算して1になるまで何回しなければなりませんか?これを行うと、
このプロセスには16ステップあり、65,536 = 2 16の場合も同様です。
しかし、各レベルで平方根をとると、
2に到達するまでに4つのステップしか必要ないことに注意してください。これはなぜですか。
まず、直感的な説明。数字nと√nには何桁ありますか?数nにはおよそlog n桁あり、√nにはおよそlog(√n)= log(n 1/2)=(1/2)log n桁です。つまり、平方根をとるたびに、数字の桁数が約半分になります。定数(たとえば、2)に落ちる前に数量を半分にすることができるのは、k O(log k)回だけなので、これは、数を減らす前にO(log log n)回しか平方根を取得できないことを意味しますある定数に(たとえば、2)。
さて、これを厳密にするためにいくつかの計算をしてみましょう。レットは上記のシーケンスを2のべき乗で書き換えます。
2 16 →2 8 →2 4 →2 2 →2 1というシーケンスに従っていることに注意してください。各反復で、2の累乗の指数を半分にカットします。これは興味深いことです。これは、既にわかっていることと関係があるためです。数値kをゼロに落とす前に、kをO(log k)の半分に分割することしかできません。
したがって、任意の数nを取り、それをn = 2 kとして記述します。nの平方根をとるたびに、この方程式の指数を半分にします。したがって、kが1以下に低下する前に適用されるO(log k)平方根のみが可能です(この場合、nは2以下に低下します)。n = 2 kなので、これはk = log 2 nであることを意味し、したがって、平方根の数はO(log k)= O(log log n)になります。したがって、問題を元の問題サイズの平方根であるサイズの部分問題に繰り返し縮小することによって機能するアルゴリズムがある場合、そのアルゴリズムはO(log log n)ステップの後で終了します。
これの実例の1つは、バンエムデボアスツリーです。(vEBツリー)データ構造。vEBツリーは、0 ... N-1の範囲の整数を格納するための特殊なデータ構造です。次のように機能します。ツリーのルートノードには√Nのポインターがあり、範囲0 ... N-を分割します。 1は、それぞれがおよそ√Nの整数の範囲を保持する√Nのバケットに入れます。これらのバケットはそれぞれ内部で√(√N)バケットに細分され、それぞれがおおよそ√(√N)要素を保持します。ツリーを走査するには、ルートから始めて、所属するバケットを決定し、適切なサブツリーで再帰的に続行します。vEBツリーの構造により、O(1)時間でどのサブツリーに下降するかを決定できるため、O(ログログN)ステップの後、ツリーの下部に到達します。したがって、vEBツリーでの検索にかかる時間はO(log log N)のみです。
別の例は、Hopcroft-Fortuneの最も近い点のペアアルゴリズムです。このアルゴリズムは、2Dポイントのコレクションから最も近い2つのポイントを見つけようとします。バケットのグリッドを作成し、それらのバケットにポイントを分配することで機能します。アルゴリズムのいずれかの時点で、√N以上のポイントを持つバケットが見つかった場合、アルゴリズムはそのバケットを再帰的に処理します。したがって、再帰の最大深度はO(log log n)であり、再帰ツリーの分析を使用すると、ツリーの各層がO(n)の作業を行っていることが示されます。したがって、アルゴリズムの合計実行時間はO(n log log n)です。
サイズO(log n)のオブジェクトに対するバイナリ検索などのアルゴリズムを使用してO(log log n)ランタイムを実現するアルゴリズムは他にもいくつかあります。たとえば、x-高速トライデータ構造は、高さO(log U)のツリーのレイヤーに対してバイナリ検索を実行するため、一部の操作のランタイムはO(log log U)です。関連するy-fastトライは、O(log U)ノードのバランスの取れたBSTを維持することにより、O(log log U)ランタイムの一部を取得し、それらのツリーでの検索を時間O(log log U)で実行できるようにします。タンゴツリーおよび関連multisplayツリー彼らはO(Nログ)項目それぞれを含むツリーを維持するため、データ構造は、その分析においてO(ログログN)用語で終わります。
他のアルゴリズムは、他の方法でランタイムO(log log n)を実現します。 補間検索では、ランタイムO(log log n)がソートされた配列内の数値を見つけることが期待されていましたが、分析はかなり複雑です。最終的に、分析は、反復回数がkに等しく、n 2 -k≤2となることを示すことで機能します。この場合、log log nが正しい解です。Cheriton-Tarjan MSTアルゴリズムのような一部のアルゴリズムは、複雑な制約付き最適化問題を解くことにより、O(log log n)を含むランタイムに到達します。
お役に立てれば!
時間の複雑さにおけるO(log log n)の因子を確認する1つの方法は、他の回答で説明されているような除算によるものですが、時間と空間/時間の間のトレードを行いたい場合、この因子を確認する別の方法があります。アルゴリズムの近似/時間と硬度/ ...そして私たちは私たちのアルゴリズムにいくつかの人工的な反復を持っています。
たとえば、SSSP(単一ソースの最短経路)には平面グラフにO(n)アルゴリズムがありますが、その複雑なアルゴリズムの前には、実行時間O(n log log n)を使用したはるかに簡単なアルゴリズム(ただしかなり難しい)がありました。アルゴリズムの基本は次のとおりです(非常に大まかな説明です。この部分の理解をスキップして、回答の他の部分を読みます)。
しかし、私のポイントは、ここでは、分割をサイズO(log n /(log log n))に選択することです。O(log n /(log log n)^ 2)のような他の除算を選択した場合、より高速に実行され、別の結果が得られます。つまり、多くの場合(近似アルゴリズムやランダム化アルゴリズム、または上記のSSSPのようなアルゴリズム)、何か(サブ問題、可能な解決策など)を反復するとき、そのトレードに対応する反復数を選択します(時間/空間/アルゴリズムの複雑さ/アルゴリズムの定数係数...)。実際の作業アルゴリズムでは、「log log n」よりも複雑なものが表示される場合があります。