xyynb!
kmp這裡,字串從1開始計數!
眾所周知,kmp是一種單串匹配演算法,把樸素演算法的o(|s|*|t|)
優化到了o(|s|+|t|)
。
如上圖,在進行樸素演算法時,如果我們已經進行了一些匹配成功,實際上我們就知道了原串的一些資訊,理論上就可以使用這個資訊來加速匹配,跳過一些絕對不可能匹配成功的情況。
所以,該怎麼做呢?這就是kmp很迷的地方之一,也是我一直看不懂kmp的乙個點。
為此,xyy
提到了border
的概念。border
即是某個字串的最長相等前字尾(不包含自己)。
有了這個定義,再結合上面的圖,就可以看到,如果在某個字元失配了,說明這個字元前的模式串t和字串s是相等的,由於border
的存在,可以直接跳過一些字串,直接跳到失配字元前的模式串t的border
,比較border
之後的字元。
一定沒有錯過什麼能夠正確匹配的情況嗎?是的,反證可以證明,要是存在,那border
就不是最長了。
也就是說,kmp分為兩個步驟,求t中每個字元前的子串對應的border
長度,然後匹配。一般把前者(每個字元前的子串對應的border
的長度)定義為fail
陣列,或者xyy
的π()函式
。
在t也很長的時候,暴力求解fail
陣列也是不可取的。
這種情況下,可以看出:
由於綜上,若π(3)=1
,可得t[1...1]==t[3...3]
又由於t[2]==t[4]
,t[1...2]==t[3...4]
所以π(4)=2=π(3)+1
。
t[i+1]==t[π(i)+1]
,則π(i+1)=π(i)+1
。
那如果t[i+1]≠t[π(i)+1]
呢?
有乙個神奇的性質,border
的border
仍然是原串的border
。
由於因此,我們可以用遞迴的方法,如果abacaba
是原串的border
,則黃串+c+綠串==藍串+c+紅串
。由於
aba
是abacaba
的border
,則黃串==綠串,藍串==紅串
。所以,
黃串==綠串==藍串==紅串
。
t[i+1]≠t[π(i)+1]
,則檢查t[i+1]==t[π(π(i))+1]
,以此類推,直至出現相等。如果真的很慘,乙個border
,那麼應該遞迴到π(i)=0
,這時,t[i+1]==0
。
綜上,求fail
陣列的**為:
void getfail()
return;
}
kmp與ac自動機
xj比賽做到一道字串題,結果發現想打個字串匹配都只會n 2了,又一次忘記了kmp 想必是當初學這玩意心理陰影面積太大了。這裡再梳理一遍kmp和ac自動機 以便下次再忘了有地方看.kmp 用於處理對於字串s,想知道它在另外某個串哪些位置出現的問題,先做預處理得到乙個失配陣列,這個陣列第i位表示s的前i...
AC自動機(KMP 字典樹)
ac自動機 kmp 字典樹 題目 輸入n個串,判斷有多少個搜尋串的子串 in out 1 47a ababc abcd abcde abcdef abcdefg abcd includeusing namespace std char str 1000000 100 struct node root...
AC自動機 建立nlogn個AC自動機
string set queries 題意 給你3種操作,1 加入乙個串到集合中。2 刪除集合中的某乙個串 3 查詢集合中的字串在給定的字串種出現幾次。同乙個串可重複 解法 建立多個ac自動機,用二進位制分組來處理。加入給你21個串 分為 16 4 1,再新增乙個串的時候,即21 1,22 16 4...