總結 字串匹配 KMP 和 拓展KMP

2021-07-11 12:56:03 字數 2911 閱讀 3308

比起ac自動機,kmp就乙個next陣列,理解了如何初始化next後就可以搞一些模板題了,下面是還不錯的學習資料,清晰易懂,自己用的模板也來自它:

next[0]=-1;j=-1

;for(i=0;i

for(i=0,flag=0,j=0;i

接下來需要更加深入地了解next陣列,許多題目需要用到它的定義來預處理字串:

xdu 1154

顯然,用2次kmp處理處字首和字尾在各點的匹配情況,用dp記錄符合要求的子串,有幾個要注意的地方:(調了2個小時t_t)

1.字首的其實位置不但要在字尾的前面,終止位置不能超過字尾的終止位置,也就是說字首不能包含字尾.

2. 

for(i=0,flag=0,j=0;iwhile(j>=0 && p[j]!=t[i])j=next[j];

i++;j++;

if(j==m)//若在此處記錄則會出現bug,因為此時匹配完成點是i-1

}

cf也有一道與上面類似的題,需要用kmp預處理最左端字首和最右端字尾

迴圈節問題

它還能用來求週期字串的迴圈節hdu1358:

性質:當且僅當len%(len-next[len])==0時,str[next[len]~len-1]為最小迴圈節

要證明它需要說明3點:

1.乙個字串str是週期串,假設s1為它的迴圈節,則str=s1 s1...s1(n個) 

推導出=>len%(len-next[len])==0成立.

2.next[len]~len-1為s1 ,len%(len-next[len])==0時 

推導出=>str為週期串,s1為最小迴圈節

3.如何保證是最小的.

證明:1.由next的性質知道,s[1~next[len]-1]與s[1~len-1]有最長的相等的字首和字尾s,很顯然s就是n-1個s1了.

2.設s1的長度為l,由於len%l==0 , str可以分解成若干個長度為l的小串,設它們從左到右依次為

a1 , a2 ... an

根據匹配關係得

a1=a2;

a2=a3;

..an-1=an;

因此a1=a2=a3...=an;

3.next[len]保證了字首與字尾最大化,如果迴圈節s1存在而s1內還有迴圈節s1',則next[len]可以向後移動,與定義矛盾.

相等的迴圈同構問題

hdu3374 string problem

分析:最大和最小的迴圈同構字串可以分開處理,求位置可以利用最小最大表示法(03wc** 周源)

求出現的次數可以用kmp掃一遍,但利用 迴圈節 可以更快地得到答案.

性質:字串str由k個最小迴圈節s1組成,則它的相等迴圈同構數為k.

證明:設相等迴圈同構數為p,我們可以利用迴圈節s1構造出k個相等的迴圈同構,於是p>=k;

下面證明p<=k:

如果p>k

假設在移動完s1到尾部前,出現了相同的迴圈同構串,不妨設此時移動的串為s2,

則利用 迴圈節性質2第1種情況的推理方法 可以知道s2為字串的乙個迴圈節

且s2的長度於是p只能等於k.

拓展kmp

有很長一段時間單純地以為拓展kmp只是kmp倒過來跑,後來發現很多問題其實無法轉換成kmp解決,於是怒學了一下拓展kmp.

首先比較一下kmp和拓展kmp解決的問題:

kmp解決了求所有主串的字首pre[i](0<=i拓展kmp解決了所有主串的字尾suf[i]字首,與模式串字首的最大匹配長度問題.

1

void

getnext() 10}

11 next[0] =i;

12 }

設模式串為str;

定義next[i]為 str 與 它的字尾suf[i]的最大公共字首長度.

r是當前已經確定匹配區間的最右端點,l是對應的左端點,即r=l+next[l]-1;

當要求next[i]時

根據 next定義 str[ l , l+next[l]-1 ] == str[ 0 , next[l]-1 ];

得到 str[ i , l+next[l]-1 ] == str[ i-l , next[l]-1 ];

設s1=str[ i , l+next[l]-1 ]; 

討論以下情況:

1. 若  i在 [l,r] 區間內  

next[i-l]的值我們已經知道,這時候需要討論:

如果  next[i-l] 小於 s1 的長度,那麼可以知道在下標為 next[i-l] 的位置必定會失配,於是next[i]=next[i-l];

如果  next[i-l] 大於或等於 s1 的長度,那麼直到r位置,我們都可以確定已經匹配上了,接下來需要確定r後面

位置的匹配情況,而此時i已經匹配了r-i+1的長度,next[i]從這個值開始計數就可以了,計數完成後i+next[i]-1

已經大於r,因此要更新   r=i+next[i]-1 , l=i ;

2.若 i不在[l,r]的區間內,即 i > r, 前面得到的資訊無法用到,於是我們需要從頭將str[i]與str[0]進行匹配,當然也要記得更新l,r.

複雜度:

2個迴圈變數i,j都是單調增的,而他們最多增加n次,因此 複雜度是線性的.

拓展kmp求迴圈節的方法參考kmp求迴圈節部分.

知道這些後可以來解決這個問題

總結 字串匹配 KMP 和 拓展KMP

比起ac自動機,kmp就乙個next陣列,理解了如何初始化next後就可以搞一些模板題了,下面是還不錯的學習資料,清晰易懂,自己用的模板也來自它 next 0 1 j 1 for i 0 i for i 0,flag 0,j 0 i 接下來需要更加深入地了解next陣列,許多題目需要用到它的定義來預...

kmp字串匹配

首先要對模式串進行預處理。預處理過程就是計算出指定位置的字首和字尾的最大相同的長度 啊啊啊啊。估計只有我乙個人能看懂 這個文章說得很清楚 比如說 a a a c b c a a a 0 1 2 0 0 0 1 2 3 void getnext int next,char par 20 int n 翻...

字串匹配 KMP

參考 從頭到尾徹底理解kmp 在字串 str 中 匹配模式串 pattern 1.計算模式串的 next 陣列 2.在字串中匹配模式串 當乙個字元匹配時,str i pattern k 繼續匹配下乙個字元 當當前字元不匹配時,根據 next 陣列移動模式字串,k next k next 陣列 描述模...