web-dev-qa-db-ja.com

単一の文字に適した検索アルゴリズムはありますか?

KMPやBoyer-Mooreなどの基本的な文字列マッチングアルゴリズムはいくつか知っていますが、それらはすべて検索する前にパターンを分析しますが、1つの文字の場合、分析するものは多くありません。では、テキストのすべての文字を比較する単純な検索よりも優れたアルゴリズムはありますか?

23
Christian

特定のテキスト内の単一の文字の出現をすべて検索するテキスト検索アルゴリズムは、テキストの各文字を少なくとも1回読み取る必要があります。これは明らかです。そして、これは1回限りの検索には十分であるため、(「線形」またはO(N)と呼ばれる実行時の順序で考えると)ここで、Nは検索する文字数です)。

ただし、実際の実装では、実行時の順序を全体的に変更するのではなく、実際の実行時間を短縮する、多数のマイクロ最適化が可能です。そして、目標が単一の文字のすべての出現を検出することではなく、最初の文字のみを検出することである場合、もちろん、最初の出現で停止することができます。それでも、その場合でも、最悪のケースでは、探している文字がテキストの最後の文字であるため、この目標の最悪の場合の実行時の順序は依然としてO(N)です。

20
Doc Brown

「干し草」が2回以上検索される場合、ヒストグラムベースのアプローチは非常に高速になります。ヒストグラムが作成された後は、ポインターを検索するだけで答えを見つけることができます。

検索されたパターンが存在するかどうかを知るだけでよい場合は、単純なカウンターが役立ちます。これを拡張して、干し草の山の中で各文字が見つかる位置、または最初に出現する位置を含めることができます。

string haystack = "agtuhvrth";
array<int, 256> histogram{0};
for(character: haystack)
     ++histogram[character];

if(histogram['a'])
    // a belongs to haystack
8
Sam

この非常に同じ文字列内の文字を複数回検索する必要がある場合、可能な方法は、文字列を小さな部分に分割し、おそらく再帰的に、これらの部分ごとにブルームフィルターを使用することです。

ブルームフィルターは、フィルターによって「表される」文字列の部分に文字がnotであるかどうかを確実に伝えることができるため、文字を検索するときに一部をスキップできます。

例として:次の文字列の場合、4つの部分(それぞれ11文字)に分割し、各部分にブルームフィルター(おそらく4バイトの大きさ)をその部分の文字で埋めることができます。

_The quick brown fox jumps over the lazy dog 
          |          |          |          |
_

検索を高速化できます。文字aの場合:ブルームフィルターに適切なハッシュ関数を使用すると、高い確率で、第1、第2、第3の部分を検索する必要がないことがわかります。したがって、33文字をチェックする必要がなく、代わりに16バイトのみをチェックする必要があります(4ブルームフィルターの場合)。これはまだO(n)であり、定数(分数)係数を使用しているだけです(これを有効にするには、より大きな部分を選択して、検索文字のハッシュ関数を計算するオーバーヘッドを最小限に抑える必要があります)。

再帰的なツリーのようなアプローチを使用すると、O(log n)に近づくはずです。

_The quick brown fox jumps over the lazy dog 
   |   |   |   |   |   |   |   |---|-X-|   |  (1 Byte)
       |       |       |       |---X---|----  (2 Byte)
               |               |-----X------  (3 Byte)
-------------------------------|-----X------  (4 Byte)
---------------------X---------------------|  (5 Byte)
_

この構成では、次のことを確認する必要があります(ここでも、幸運でフィルターの1つから誤検知が発生しなかったと想定しています)。

_5 + 2*4 + 3 + 2*2 + 2*1 bytes
_

最後の部分に到達するには(aが見つかるまで3文字をチェックする必要があります)。

良い(上記の方が良い)サブディビジョンスキームを使用すると、かなり良い結果が得られます。 (注:ツリーのルートにあるブルームフィルターは、誤検知の可能性を低くするために、例に示すように、葉の近くよりも大きくする必要があります)

1
Daniel Jour

文字列が複数回検索される場合(一般的な「検索」問題)、解はO(1)になります。解決策は、インデックスを作成することです。

例:

マップ。キーは文字で、値は文字列内のその文字のインデックスのリストです。

これにより、1回のマップ検索で答えを得ることができます。

1
Shamit Verma