ここに私をしばらく悩ませてきた問題があります。さんが言ってみましょう文字列は、1と0のシーケンスであり、そしてワイルドカード文字列は 1のシーケンスであり、0、および?の。すべての文字列とワイルドカード文字列は同じ長さです。これらは標準のUNIXワイルドカードです。10 ?? 1は10011、10111などと一致します。その位置で1または0に一致します。場合はおよびWは、ワイルドカード文字列である、我々は書きV ≤ Wにマッチしたすべての文字列ならばvはまたで一致しているワットを。
問題:集合与えられたワイルドカード文字列の、およびクエリV(ワイルドカード文字列)は、存在しないwが∈ SようにV ≤ ワット?そうでない場合、vをSに効率的に追加できますか?
ここに明らかなソリューション(kは文字列のサイズ、mはRAMのワードサイズ(通常32または64)):リストの各要素を調べ、条件をテストします(2または3回の操作で実行できます)ビットいじりを使用して)。また、テストであれば、V≥wは任意の項目について成り立つワットながら、僕らだスキャン。vがテストに失敗した場合は、vをセットに追加し、マークしたwを削除します。
しかし、それは十分に速くありません。ソリューション、または完全な世界では、基数ツリー(O (k ))に似た複雑さがあったら、それは本当にすばらしいでしょう。クエリはほぼ正確であることがもOKです:場合、であるV ≤ wが、その後、yesまたはno返しません。しかし、条件が成立しない場合は、間違いなくノーを返します。
これは最悪の場合の複雑さには役立ちませんが、内のすべての要素はワイルドカード文字列で区切られていると想定できます。つまり、いくつか存在するVなど、すべてのそれのw ∈ S、V ≥ wは。
私が試したアイデア
- ワイルドカード文字列は結合セミラティスを形成します。ワイルドカード文字列を保持するn-aryツリーを持つことができます。葉はワイルドカード文字列であり、枝はすべての子の結合を表します。クエリと結合が比較できない場合、そのブランチのすべての子と比較するために時間を無駄にする必要はありません。さらに、更新を行い、その更新が結合よりも大きい場合は、ブランチ全体を削除するだけで済みます。残念ながら、これは最悪の場合でも依然としてであり、要素を追加するためにツリーをスキャンするときに、常に「最適な」結合を見つけることができるとは限りません。
- 基数トライを形成できます。Sはいくつかのワイルドカード文字列で区切られていることがわかります。?0?0であると仮定します。次に、トライのすべてのブランチは、文字列の1番目と3番目のビットにある必要があります。クエリで分岐している現在のビットが1の場合、?そして1つの枝; 0の場合、?そして0の枝; ?の場合、チェックするのは?ブランチ。潜在的に複数のブランチをとる必要があるため、これはあまりよくありません(同じ理由でトライを更新するのは困難です)。マッチングは非常に高速な操作であるため、ツリー内で多くのトラバースを実行する単純な戦略と比較すると、害があります(ポインターの束を追跡することは、いくつかのORやANDを実行するよりもはるかにコストがかかります)。
関連作業
ネットワーキングコミュニティでは、この問題は「パケット分類」として現れます。ここでは、既知のアルゴリズムとデータ構造の良い調査を示します。残念ながら、ほとんどの場合、ワイルドカード文字列はプレフィックスにのみ一致すると想定されており、クエリはそのような文字列のタプルです。もちろん、常に次の基準を満たすように一般的なワイルドカード文字列を変換できます:1?00?1 ?? は(1、?、0、0、?、1、?、?)です。ただし、これは効率的ではありません。他の前提として、これらのタプルは「色」に関連付けられており、クエリで色が返される必要があります(一致した色だけではありません)。これは、タプルを順序付けする必要があるため(または(0、?)と(?、1)のどちらが(0、1)に一致するかが不明確)、問題がはるかに困難になります。
アルゴリズムコミュニティでは、「気にしない」と一致する部分文字列の検索に関連する多くの結果を見つけました。これはかなり難しい問題であり、実際にはどのテクニックも利用できません。
結論として
助けてくれてありがとう!