範囲内の文字列内の異なる部分文字列の数


7

文字列の長さが、LCP配列を使用すると、個別の部分文字列の数を線形時間で見つけることができます。文字列全体で一意の部分文字列の数を求める代わりに、インデックスを含むクエリ、が、文字列指定されたクエリ範囲内の異なる部分文字列の数を求めます。。SnSq(i,j)0ij<nS[i..j]

私のアプローチは、LCP配列の線形時間構築を各クエリに適用することです。複雑さを与えます。クエリの数はオーダーに増加する可能性があるため、すべてのクエリに応答するとます。O(|q|n)nO(n2)

すべてのクエリの線形時間よりも、それを行うことができますか?

一般に、サフィックス配列、サフィックスツリー、lcp配列がすでにある文字列の1つのプロセスサブ文字列がそれらの構造に関連しなくなった場合、もう一度最初から構築する必要がありますか?


入力と出力のサイズは自然な下限のようです。
ラファエル

1
私はこれについて考える時間はありませんが、これらの複雑な構造から(競争プログラミングで)セグメントツリーを構築することはかなり標準的です。おそらく、サフィックス配列/ツリーなどの場合です。高速な「結合」操作を定義するのは賢い必要があります(これは、父親ノードと子ノードで使用されるか、最後に、間隔をカバーするすべての葉の結果を結合するために使用されます)。
md5 2017年

クエリの数はである順序付けられたペアの数であるため、複雑度は必要がありますi,j(n(n+1))/2O(n3)
user11171

@ md5部分文字列の数に追加の逆数がないため、セグメントツリー(またはフェンウィックツリー)ベースのソリューションは機能しないと思います。
user11171 2018

回答:


0

質問はクエリの数をにする動機にはなりません。一意の可能なクエリの数は順序付けられたペアの数、つまりため、これは任意の最悪のケースのようです。O(n)O(n2)

以下は、Ukkonenのアルゴリズムを使用して増分的に構築された(暗黙の)サフィックスツリーに基づく場合の時間の複雑性がより優れた2つの異なるソリューションです。両方の溶液は、前処理に基づいており、複雑有するクエリの集合です。2番目のソリューションは、すべてのクエリの幅が同じである場合、実行されます。O(n2)O(n2+|Q|)QO(n+|Q|)

解決策1-すべての一意のクエリを前処理する

のサフィックスを反復処理します。各サフィックス、Ukkonenのアルゴリズムを使用してのサフィックスツリーをします。を現在のサフィックスツリーに更新した後、ツリーサイズを行列の位置に格納します。範囲のクエリは、行列要素によって応答されます。SSi=S[i..n]Sij(i,i+j1)[x,y](x,y)

接尾辞ツリーのサイズは接尾辞ツリーと一緒に保存でき、Ukkonenのアルゴリズムの更新手順を変更することにより、各ステップで一定の時間で更新できます。更新ごとに、サイズは現在の葉の数だけ増加します。

解決策2-一意のクエリ幅を前処理する

このソリューションは実装が困難ですが、クエリの幅が少ない場合は前処理作業が少なくて済みます。クエリ幅が1つしかない場合、前処理には時間かかります。O(n)

クエリの幅ごとに、幅スライディングウィンドウを使用して、サフィックスツリーを段階的に構築します。ツリーから最も長いサフィックスを削除して、ウィンドウの左側の1文字から始まるサフィックスを削除します。各ステップで、スライディングウィンドウ内の現在の部分文字列の数はツリーのサイズです。ww

その後、事前計算の結果を使用して、すべてのクエリに線形時間で応答できます。

注:最長のサフィックスを削除するには、サフィックスツリーの最も古いリーフを削除します。正しく実装するのは簡単ではありません。


これは少しずれているようです。タスクは、考えられるすべてのクエリに答えるのではなく、指定されたいくつかのに答えることです。O(n2)q
Gassa

質問のポイントだった一般的なケースの質問に答えました。クエリの数が少ない特殊なケースでは、質問の作成者によって提案されたソリューションは、実際にはより速く実行されます。有効な解の出力数は、サイズはqO(n2)(重複するクエリは無視)であるため、可能なソリューションはすべて実行する必要があります。O(n2)または遅い。私の提案したソリューションには時間がかかりますO(n2)前処理を行うと、各クエリに一定の時間で応答できます。
user11171 2018

再び、 qパラメータです。質問がクエリの数に明確に関心があるq であること Θ(n)ではなく Θ(1) また Θ(n2)。の答えq クエリのサイズ Θ(q) する必要はありません Θ(n2)
Gassa

クエリの数が適切である理由 n?著者による見落としではないにしても、それは恣意的な条件のようです。
user11171 2018

問題ステートメント全体は、同程度の恣意的なものです。ただし、これは競合プログラミングにおける典型的なデータ構造の問題のようであり、そのためn2クエリはOPが探すものです。私は賭けますn そして q から独立したパラメータです 1100000 など、時間制限は数秒ですので、 Oq 解決策はタイムアウトしますが、より良いもの Oqしません。
Gassa

0

有る O(nn+|Q|n) オフラインソリューション。

  1. 要素を並べ替える (i,j)Q 昇順 j
  2. それらを配布する n バケツなので、 (i,j) バケット番号に入ります in
  3. バケットごとに b そして各クエリ (i,j) その中に、サフィックスツリーを構築します S[b,j]
  4. バケット内のクエリごとに、左側から冗長な文字を削除し、回答を報告します。

ステップ3は O(n) バケットごとに、Ukkonenのアルゴリズムと j 昇順で移動します。

ステップ4は O(n) クエリごとに、削除するため n ツリーからの最長サフィックスは O(n)。間接層を使用して、元のサフィックスツリーへの変更を回避できることに注意してください。


別個の部分文字列の数は、ルートで始まり、その下に葉が1つしかないノードで終わるサフィックスツリー内のパスの数です。これらのパス数をメモに明示的に保存していますか?もしそうなら、O(1)時間の最初の文字を削除するときに、どのように更新しますか?まであり得るnそれらの(最初の文字がブロック内で一意である場合)。そうでない場合、その場でそれらをどのように計算しますか?
j_random_hacker

@j_random_hacker Ukkonenのアルゴリズムは、いわゆる暗黙のサフィックスツリーを構築します。異なる部分文字列の数は、そのエッジの長さの合計です(つまり、対応するトライのサイズ)。
Dmitri Urbanowicz 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.