最後一個月的倔強,希望心想事成。
1. next數組
首先是next數組。kmp的核心無非於next數組:
- 出現失配的時候,因爲前 j 個字符有 個最長公共前後綴,就說明現在這裏失配了但是前面的有 個字符是不用再次匹配的,所以模式串向右移動 個單位,即 。
- 值得一提的是:
- 否則該串需添加 len - n%len 個字符才能形成循環串。(n%len在這裏爲串中後綴屬於循環串的一部分)
void getnexts(){
ll i=0,j=-1;
nexts[i]=j;
while(i<m){
if(j==-1||p[i]==p[j]) nexts[++i]=++j;
else j=nexts[j];
}
}
2. kmp匹配過程
如果說next數組的匹配過程是模式串匹配自身,那麼kmp的過程就是模式串匹配文本串。
說實話也就是回溯過程與暴力不一樣而已,但是這就是一個很大的優化點。
匹配結束後,如果說明模式串匹配結束,即在文本串中出現在的位置上。
ll kmp(){
getsnexts();
ll i=0,j=0;
while(i<n&&j<m){
if(j==-1||s[i]==p[j]) ++i,++j;
else j=nexts[j];
}
if(j==m) return i-j;
return -1;
}
3. 有點模板且需要一點思考的題 (適合初學者/複習)
1.next求補齊循環節 :
運用上述next的內容即可。
2.next求有多少子串爲其原串的前綴 :
提示:next[i]表示最長公共前後綴,那麼這個後綴長度即爲匹配的前綴。
3.求模式串前綴與文本串後綴的最大匹配 :
不難想到把文本串皆在模式串後面,但要考慮一下的情況。
4.next求循環週期 :
運用上述next的內容即可。
5.求模式串中 E+A+E+B+E(其中AB爲任意長度的子串) E的最大長度 :
find的暴力美學。
6.next遍歷求循環節+循環週期 :
運用上述next的內容即可。
7.next求既是前綴又是後綴的子串長度 :
運用上述next的內容即可。