アルゴリズム1:RKアルゴリズム
アルゴリズムの説明:
(1)計算モデル列車ハッシュコード
モード1:加算ビット単位;
実施例2:進数は、ABCのように、小数26に変換されるよう= 1x26 ^ 2 + 2x26 ^ 1 + 4x26 ^ 0。
図2の実施形態の欠点:長い文字列、対応する小数の数は非常に大きくなり
(2)増分メインストリングを計算します
例えば:メインストリング:abbcefg;パターン列BCE
まず、計算ABB、BBC第2の算出:新しいもの順Hahcode =ハッシュコード- '' + 'C '
(3)チェックハッシュ衝突
// 20200306 の#include <iostreamの> の#include <cstdioを> する#include <CStringの> 使用して 名前空間はstdを、 const int型 MAXN = 1000年。 チャーパターン[MAXN]、メジャー[MAXN]。 int型のハッシュコード(CHAR * ARR、INT、開始INTの端){ int型の和= 0 。 用(INT ; I <END; I =始めるI ++ ){ 合計 + =(INT)ARR [I] - ' ' + 1。//「」97であるのASCII } リターン合計。 } int型 changehashcode(INT sumori、INT、開始のint {端)に 戻り sumori -主要[begin- 1 +メジャー] [エンド1 ]。// + 96から96 = 0 } ブール hashcollision(INT、開始int型エンド){ BOOLの状態= 偽。 用(INT iは=始まる; I <END; I ++ ){ 場合(!主要な[I] =パターン[1-が始まる]){ 状態= 真; 休憩; } } もし(状態)に戻り 、真。 それ以外の リターン はfalse ; } int型のmain(){ int型 POS = - 1 。 scanf関数(" %sの\ nは%sの" 、パターン、主要な); INT lenp = STRLEN(パターン)。 int型 lenm = strlen関数(メジャー); INT hashp =ハッシュコード(パターン、0 、lenp)。 int型 hashm =ハッシュコード(メジャー、0 、lenp)。 もし(!hashm == hashp && hashcollision(0、lenp))の戻り 0 ; 以下のために(INT iが= 1 ; I <lenm-lenp; I ++ ){ hashm = changehashcode(hashm、I、I + lenp)。 もし(hashm = hashp!)続けます。 それ以外の 場合(hashcollision(I、I + lenp))続けます。 他の{ POS = I; 休憩; } } COUT << POS。 リターン 0 ; } / * ---テスト--- ECB abbcefgh //衝突 ECB abcbefgh * /
アルゴリズム2:KMPアルゴリズム
1.次の配列とは何ですか?
次の[i]がサブS [0 ... i]が 最大値に等しいプレフィックスの最後の添字に接頭辞と接尾辞 。(また、接頭辞と接尾辞の同じ長さまで)
接頭語は何ですか?サブストリングS [0 ... i]の接頭辞と接尾辞等しい長さの接頭辞、S [... I]サフィックスとしてS [0 ... K(K <I)です。(kは= I、即ち、ストリング自体ではないことに注意!)、すなわち数k以降ゼロから、最後の文字の番号kを番目(K <I)から前進を開始します
例えば:S [] = abababc
私のサブストリング、= 0の場合、kはiが0 = <kの値ができないので、次の[0] = -1。
私はABのサブストリング、1 =場合、K = 0 <iは、1 =接頭辞、接尾辞B、等しくありません
ので、次の[1] = -1。
iがサブストリング、2 =ときABA、K = 0 <iは、2 =サフィックスプレフィックス、等しい、K = 0
K = 1 <I = 2、AB&接頭辞、接尾辞BAは、等しくありません
したがって、接尾辞の前に最大値に等しい(すなわち、最大k)が0であり、次の[2] = K = 0。
私はABABのサブストリング、3 =とき、K = 0 <I = 3で、接頭辞、B、不等サフィックス
K = 1 <iは、接頭AB、接尾ABは、に等しく、3 = K = 1
K = 2 <I 3、プレフィックスABA、BABサフィックスを=、等しくありません
したがって、接尾辞の前に最大値に等しい(すなわち、最大k)は1であり、次の[3] = K = 1。
私は4,5,6 =場合は、共感。
iが7(strlenを(S)= 7)、サブストリングabababc、K = 0 <iは、7 =プレフィックス=とき、接尾辞C、等しくありません。もはや等しく、それらが等しくないされる状況が終了することができませんのでOK、kのこの時間値は、ダウン続行する必要はありません。[Kに等しい増分し続け、kは、直ちに、次の[I] = K-1を終了するために等しくありません]。
最終的に得られた次配列[-1、-1,0,1,2,3、-1]。
2.どのように次の配列を取得するには?(以下の再帰的方法を使用するように、より複雑な場合に取らアルゴリズム次の配列を求めて上記に例示)
私たちは、[i]は、次のシーク[I-1]次のベースになります。
我々が算出したと[I-1]、それはJに等しい行いたいことがあり、次の(されたフロント等しいサフィックスS [0 ... I]の最長の長さがJであり、我々は場合読み続け、) 、アップサフィックスの最大長とは、前者に等しい元のいずれかに基づいて増加し、次等しいサフィックスまでの最長の長さ前に、ある[I-1]を+1。
(分から:接尾語長(x)はstrlenをXYXの最も長い文字列に等しい前に、最初のサフィックス長は、strlenを(XAより最長可能xyxaに等しい)と する場合にのみとサフィックスはxyxa等しいSTRLEN(XA)の前に最長の長さに等しいです。場合Y == A [0] )
言い換えれば、私たちは、新しい文字とyを読んで判断する[0]に等しいであり、y [0]とは何ですか?最後に添字が+1のプレフィックスは前者される前に読み出した文字列は、文字に対応する添え字として最長のサフィックスに等しいことが、文字に対応する添字J + 1、すなわち、です。
== Y [0]、次の[I] = J + 1ができれば。
場合は!= Yは、[0]、どのようにしますか?
マッチングを開始するスクラッチ(J = -1)から直感的なアイデアは、そのようなアプローチは、我々は、最も近いJを満たすための要件(== S [J + 1返すことができるように、あまりにも暴力的である ]) 場所。言い換えれば、我々はによってできるだけ文字の後の文字列のxyxa xの最初のを見つける必要がある、我々は、x UWに分割した後、我々は、文字列wazyuwaをしなければならない、取り壊しが最初のx WAZであることを前提としていできるだけ小さい長さZ(できるだけ大きく長さw)。では、どのような場所でWAZを見つけるのですか?今、私たちは、値に対応する次の文字列の意味が保存されているZの文字列の最後の文字の位置を知っている サフィックス文字列は最長プレフィックスWAZに等しい前の 最後のビットインデックス、それだけ添字と仮定することができます対応する文字(そうでない場合、我々は周期的J =次の[J]にせ、またはそれがエンドツー1に遭遇するまで)、文字列がZ WAなり、その後、全体IS前wazyuwaの最も長い文字列に等しいです接尾語の長さは(WA)strlenをされています。
3. KMPアルゴリズムは何ですか?
我々は、上記の要件次の配列プロセスであることが見出された文字列「自己整合」、サブの文字列の文字列[0,1,2 ... i]はsは見つける[0,1に与えられるプロセス、 ... K(K <i)とS [...、i]はそれほどできるだけ大きく二つのサブストリングを正確に等しく、Kこと。次いで、所定のパターンに一致する同じ文字列がパターン文字列に、テキストのメインストリング所与のサブストリングマッチングサブストリングを指し、パターン、プロセスアレイと次の文字列同様の処理モードに一致する文字列を検索します。
そのために求めているのプロセスは、次の配列を模倣、我々はメインテキスト文字列パターン文字列パターンの最初の文字と一致する必要があります。彼らが等しい場合、我々はあなたが不平等な状況のパターンを発生していない場合は、この時間は、我々はパターン位置を移動したい、......最後に2つ目の文字のテキストとパターンに一致し続け、そしてどのように1つのビットモバイル、その後、BFアルゴリズムに退化。そこでここでは正確に行うために移動する必要がありますか?私たちは、パターン文字列は、次の[i]の配列パターンはサブストリングパターン[0,1 .....、i]の列に記録されていることを知っている最後の添字をKの前に接尾辞が、つまり接頭辞最長に等しく、パターン[0、... k]とパターン[M、...、I(M = IK)は、同じ文字列です。ミスマッチは、パターン[M、その後、一致している[I + 1]とのパターンを言うことにあるテキスト[I + 1]、[0、...、i]とテキスト[I 0、...]は、パターンを発生します...、i]は、テキスト[M、... i]が一致し、パターン[0、...、k]とテキスト[M、... i]が一致する場合、我々は、[位置合わせパターンを続行しますK + 1]、テキスト[I + 1]のラインに等しく、及びk + 1]は次の[I + 1に等しいです。
4.まとめ
次の配列は、正確に何の意味?
(1)複数のサブストリング[0 ... I]は、 最大値に等しいプレフィックスの最後の添字に接頭辞と接尾辞。
(2)のS [0 ... i]はサブストリング 最長接尾語の長さが前面に等しいです。
一致しない場合(3)メインストリングとパターンマッチングは、J + 1、jが退避位置です。
演習に対応するアルゴリズム5.KMP:羅区OJ
ACコード:
// 20200306 の#include <iostreamの> の#include <cstdioを> する#include <CStringの> 使用して 名前空間はstdを、 const int型 MAXN = 1000000 ; チャーパターン[MAXN]、テキスト[MAXN]。 int型の次の[MAXN]。 INTの値[MAXN]。// LOGU OJに結果を格納 ボイドgetNextを(){ int型 LEN = STRLEN(パターン)。 次の[ 0 ] = - 1 。 INT J =次の[ 0 ]。 以下のための(int型 I = 1; I <lenは、I ++ ){ 一方(J = - !1つの &&パターン[I] =パターン[J +!1 ]){ J = 次の[J]。 } 場合(パターン[I] ==パターン[J + 1 ])J ++ 。 次の[I] = J。 } } INT KMP(){ getNextを()。 INT lenpt = STRLEN(パターン)。 int型 lentx = strlen関数(テキスト); INT J =次の[ 0 ]。 int型 ANS = 0 ; 以下のための(int型 I =0 ; I <lentx; I ++ ){ ながら!(J = - 1つの!&&テキスト[I] =パターン[J + 1 ]){ J = 次の[J]。 } であれば(テキスト[I] ==パターン[J + 1 ])J ++ 。 もし(J == lenpt - 1 ){ 値[ANS ++] = I + 1 - J。 J = 次の[J]。 } } 戻りANSを、 } int型のmain(){ scanf関数(" %sの\ n%sの" 、テキスト、パターン)。 int型ANS = KMP()。 以下のために(INT iが= 0 ; I <ANS; I ++)COUT <<値[I] << ENDL。 INT LEN = STRLEN(パターン)。 以下のために(INT iが= 0 ; I <LEN; I ++)COUT <<次の[I] + 1 << " "。// LOGU OJに調整します }
参考文献:
"アルゴリズム・ノート" P455〜P464 [1]胡、