プレフィックスパリティ問題のアルゴリズム


8

プレフィックスパリティの問題は、次のように定義できます。長さ文字列が与えられ、最初はすべての文字がです。次に、次のような更新をサポートできるデータ構造を構築します。n 0Sn0

  1. 特定のについて、をまたは変更しますS [ i ] 0 1iS[i]01
  2. 与えられたに対して、のパリティを見つけます。S [ 1 ] + S [ 2 ] + + S [ i ]iS[1]+S[2]+...+S[i]

私の頭の上から、データ構造を構築するために線形空間と線形前処理時間のみを使用しながら、時間でこれらのタイプのクエリをサポートできるソリューションがあり。葉が個々の文字に対応する文字列の上に完全なバイナリ検索ツリーを構築し、すべての内部ノードに、そのノードで定義されたサブツリーで葉であるすべての文字の合計を格納するという考え方です。このようにして、両方の更新を時間で簡単にサポートできます。S O log n O(logn)SO(logn)

しかし、私はこの問題の下限を証明する論文を見つけました。更新についてはよりも優れているとは言えず、次の論文も見つけましたhttp://link.springer.com/chapter/10.1007%2F3-540-51542-9_5、およびpdfへの直接リンク。その範囲を達成するアルゴリズムを提供するため、最適です。O(lognloglogn)

このアルゴリズムを理解したいと思いますが、説明は1ページのようで、多くの詳細が欠落しています。

だから私はこの問題に関する他の情報源があるのか​​と思っていました。何かを見つけるのが非常に難しいと思いますか、それともこれが唯一の情報源ですか?

前もって感謝します

回答:


9

リンクした論文をざっと読んだ。その論文で与えられた考えに基づいて、各操作にバインドされた時間を取得する単純なデータ構造を次に示します。O(lognloglogn)

あなたはあなたの質問であなたはこれをスピードアップするためにバランスのとれた拡張ツリーを使うことができると述べました。特に、バイナリツリーがあり、各ノードに左のサブツリーのパリティを追加する場合は、それぞれ時間で更新と検索を実行できます。これは高速ですが、十分な速度ではありません。O(logn)

ここで、以下のアイデアの一般化を検討してください。二分木を使用する代わりに、分岐因数多元木を使用するとします。各ノードの各キーに先行するすべてのサブツリーのパリティを追加します(これにより、左側のサブツリーのパリティを格納するという考え方が一般化されます)。ここで、このツリーでルックアップまたは更新を行う方法について考えてみましょう。ルックアップを行うには、以前から少し変更したバイナリツリールックアップアルゴリズムを使用します。各ステップで、各ノードで純粋に各サブツリーの左側にサブツリーのパリティを累積して、ツリーの上部から下部に向かってウォークします。この場合、ツリーの高さはなり、ノードごとに作業を行うため、ルックアップのコストはO log k n O 1 O log k n kO(logkn)O(1)O(logkn)

ただし、この設定では、更新を行うコストが増加します。特に、要素のパリティを変更する場合は、ツリーの最下部から最上部に向かって上に移動し、パス上のすべてのノードのすべてのキーの格納されたパリティを上方向に変更する必要があります。あるノードとあたりキー葉から上方の経路上のノードは、このような動作を行うコストがされるので、、これは遅すぎます。どういうわけかこの余分な項を排除できれば、ビジネスに参入できます。O log k n O k log k n = O kkO(logkn)kO(klogkn)=O(klogklogn)k

この論文の洞察は次のとおりです。最初の問題について考えると、サイズ配列があり、プレフィックスパリティを計算できるようにしたいと考えました。私たちは、今持っているの各ノードで、我々はサイズのアレイ上のプレフィックスパリティ問題を解決できるようにする必要があり、進ツリー各ノードは、その下の層についての情報をキャッシュするので、それぞれを。上記のデータ構造では、プレフィックスパリティの配列を格納するだけで各ノードのプレフィックスパリティの問題を解決しました。つまり、更新を実行する必要がある場合、コストはです。このペーパーの洞察は、各ノードでより巧妙なデータ構造を使用することにより、これらの更新を大幅に効率的に実行できるということです。k k O k nkkO(k)

kk2kkkkk2kkkkikiO(logkn)O(logkn)O(1)

この論文の著者は、を選択すると、k=lgn2lgn22lgn2=lgn2n=o(n)O(logkn)=O(lognloglgn2)=O(lognloglogn)o(n)O(n)

したがって、要約すると、アイデアは次のとおりです。

  • k
  • kk
  • ツリーの各ノードでこの事前計算されたデータ構造を使用します。
  • 選択k=lgn2O(lognloglogn)
  • 事前計算が価値のあるものになるまで、各ノードで一時的な置換データ構造を使用することにより、事前の事前計算コストを回避します。

全体として、それは賢いデータ構造です。この質問をしてリンクしてくれてありがとう-その過程で多くのことを学びました!

O(logn)O(lognloglogn)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.