サフィックス配列を使用して2つの文字列の最長共通部分文字列を計算する


15

複雑さで接尾辞配列を作成する方法を学んだ後、接尾辞配列の用途を発見することに興味があります。これらの1つは、時間で2つの文字列間の最長共通部分文字列を見つけることです。インターネットで次のアルゴリズムを見つけました。O(N)O(N)

  1. 2つの文字列とBを1つの文字列ABにマージしますABAB
  2. ABの接尾辞配列を計算しますAB
  3. LCP(最長共通プレフィックス)配列を計算します
  4. 答えは最大値LCP[i]

私はそれを実装しようとしましたが、多くの実装の詳細は言われていなかったので(つまり、文字列を連結するとき、それらの間に特殊文字を入れる必要があります()?)、私のコードは多くのテストケースで失敗しました。誰かがこのアルゴリズムについて詳しく説明できますか?AcB

前もって感謝します。

注:このアルゴリズムの正確性は保証しません。私はブログでそれを見つけました、そして、それが機能していると確信がありません。間違っていると思われる場合は、別のアルゴリズムを提案してください。


3
アルゴリズムを実装する前に、なぜ機能するのかを理解してください。これは、2つの文字列を連結する方法などの質問に答えるのに役立ちます。
ユヴァルフィルマス

3
このアルゴリズムの正確性には疑問があります。と取り私が読むと、それはを返しますが、これは間違っています。b c d a b c dabcdabcdbcdabcd
ハウル

回答:


19

アルゴリズムが正しくありません。文字列の接尾辞配列とLCP配列の計算方法、つまり効率的な実装を知っていると思います。コメントで指摘されているように、各コンポーネントが何であり、なぜ機能するのかを理解する必要があります。

まず、文字列の接尾辞配列()です。接尾辞配列は、基本的に、昇順の辞書式順序で配置された文字列Sのすべての接尾辞です。より具体的には、値S A [ I ]でのサフィックスことを示しSが位置からS A [ I ]がランク付けされている私はすべてのサフィックスの辞書式順序でSSASSA[i]SSA[i]iS

次は配列です。L C P [ i ]は、S A [ i 1 ]S A [ i ]から始まるサフィックス間の最長共通プレフィックスの長さを示します。つまり、辞書式順序で配置された場合、Sの 2つの連続するサフィックスの中で最も長い共通プレフィックスの長さを追跡します。LCPLCP[i]SA[i1]SA[i]S

一例として、文字列を検討。辞書順の接尾辞は{ a a b b a b c a a b c a b a b c a b b a b c a b c a c a }なので、S A = [ 7 1S=abbabca{a,abbabca,abca,babca,bbabca,bca,ca} 1-インデックス配列のために。L C Pの配列は次のようになり L C P = [ - 1 2 0 1 1 0 ]SA=[7,1,4,3,2,5,6]LCPLCP=[,1,2,0,1,1,0]

ここで、2つの文字列Bを指定すると、それらをS = A Bとして連結します。ABの両方に存在しない文字です。このような文字を選択する理由はa b d a b da b dの2つの接尾辞のLCPを計算するときに、最初の文字列の終わりで比較が途切れるからです(1回だけ発生するため、 2つの異なる接尾辞が同じ位置にあることはありません)、他の文字列に「オーバーフロー」しません。ABS=A#B#ABab#dabdabd

これで、配列の連続した値のみを表示する必要がある理由を確認できるはずです(引数は矛盾とS Aの接尾辞が辞書式順序であるという事実に基づいています)。チェック保つL C Pの最大値のアレイように比較される2つのサフィックスが同じ元の文字列に属していないが。それらが同じ元の文字列に属さない場合(一方はAで始まり、もう一方はBで始まる)、そのような最大値は最大の共通部分文字列の長さです。LCPSALCPAB

例として、およびB = b cを考えます。次に、S = a b c a b c b cです。ソートされたサフィックスは{ a b c b c a b c a b c b c b c b c b c b c aA=abcabcB=bcS=abcabc#bcS A{abc#bc,abcabc#bc,bc,bc#bc,bcabc#bc,c,c#bc,cabc#bc}
SA=[4,1,8,5,2,9,6,3,7]LCP=[,3,0,2,2,0,1,1,0]

現在、最大値はですが、S A [ 1 ]S A [ 2 ]であり、どちらも文字列Aで始まります。したがって、それは無視します。一方、L C P [ 4 ] = 2S A [ 3 ]Bの接尾辞b cに対応)およびS A [ 4 ]LCP[2]=3SA[1]SA[2]ALCP[4]=2SA[3]bcBSA[4]Aのサフィックスに対応)。したがって、これは2つの文字列の中で最も長い共通部分文字列です。実際のサブストリングを取得するためには、長さ取る2(最大値の可能L C Pのいずれかから始まるサブストリング)S A [ 3 ]又はS A [ 4 ]であり、B 、Cbcabc#bcA2 LCPSA[3]SA[4]bc


1
優れた説明が、私は例がビット間違っていると思い、ソートされた接尾辞は以下のとおりです{#bc,abc#bc,abcabc#bc,bc,bc#bc,bcabc#bc,c,c#bc,cabc#bc}SA=[7,4,1,8,5,2,9,6,3]LCP=[−,0,3,0,2,2,0,1,1]
ソール・マルティネスVidals

1

オンラインで見つけたアルゴリズムは完全に正しいわけではありません。Pareshが述べたように、彼の例では失敗します。

ただし、LCPの確認中に、異なる文字列の部分文字列のLCPのみを確認するようにします。たとえば、文字列Aと文字列BのLCSを見つけている場合、LCPの確認中に接尾辞配列の隣接するエントリが同じ文字列からのものでないことを確認する必要があります。

詳細はこちら


1
「この答え」と言うとき、あなた自身の答えですか、それとも他の答えですか?回答ボックスを使用して質問に回答してください。他の回答にコメントすることはできません。十分な評判を獲得したら、他の回答にコメントを残すことができます。
デビッドリチャービー

0

文字セットの一部ではない文字がセパレータとして使用され、サフィックス/プレフィックス配列が構築され、セパレータを含むすべての文字列を除外する場合、おそらくあなたが引用するアルゴリズムのようなものは実際に動作するはずだと思います、おそらくデザイナー。これは基本的に、2つの別々の文字列の接尾辞/接頭辞配列を作成することと同じです。

アルゴリズムへのリンクを投稿しておくと、将来の参照に役立ちます。ウィキペディアには、このためのアルゴリズムが擬似コードと他の多くのアルゴリズムに含まれていることに注意してください。また、オンラインで利用可能なほとんどの標準言語の実装があります。

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