這個演算法主要靠畫圖理解,於是學習的時候畫了不少圖,正好寫篇部落格。
擴充套件kmp能解決的問題:
給定兩個串\(s,t\),對於s的每乙個字尾\(s[i...n]\)求和\(t\)的\(lcp\)。
設\(exnxt_i\)表示字尾\(s[i...n]\)求和\(t\)的\(lcp\),我們要做的就是求所有\(exnxt_i\)。
我們先對\(t\)處理出\(nxt_i\)表示\(t\)的字尾\(t[i...m]\)和\(t\)的\(lcp\),如何處理之後再說。
1.如何求\(exnxt\):
假設我們已經求出了\([1,i-1]\)的\(exnxt\),我們現在要求\(exnxt_i\)。
我們維護\(p\)表示對於\([1,i-1]\)它們在\(s\)上最遠和\(t\)匹配到了**,用式子說就是\(max_(j+extnxt_j-1)\),並且我們維護這是在哪個點取到的,記為\(p0\)。
先上一張圖:
我們現在是在\(p0\)匹配好的時候,我們觀察\(i\)的位置,不難發現\(i\)此時對應著\(i-p0+1\)。
我們設\(l=nxt_\),那麼根據已知資訊,即\(nxt\)的定義,我們能知道:
\(t[1...l]=t[i+p0-1...(i+p0-1)+l-1]=s[i...i+l-1]\)
即下圖三線相等:
這時如果\(i+l-1(注意不能取等,我們並不知道\(p\)之後的資訊),那麼我們實際已經求完了,此時\(exnxt_i=l\)。
**非常簡單(**中\(r\)即為\(p\)):
if(i+nxt[i-p0+1]-1接下來考慮如果\(i+l-1\geqslant p\)會怎樣:
這時我們只能知道如下三條線是相等的,即:
\(t[1...p-i+1]=t[i-p0+1...(i-p0+1)+(p-i+1)-1]=s[i...i+(p-i+1)-1]\)
於是我們讓\(extnxt_i\)先有乙個候選答案\(p-i+1\)之後,我們暴力匹配,不斷擴充套件\(extnxt_i\)。
**是這樣的(**中的\(r\)就是\(p\)):
exnxt[i]=max(r-i+1,0);
while(s[i+exnxt[i]]==t[exnxt[i]+1])exnxt[i]++;
之後我們讓\(p0=i\),更新\(p\)的值(**中的\(r\)就是\(p\)):
p0=i,r=i+exnxt[i]-1;
感性理解的話因為\(p\)的增長是\(o(n)\)的,所以整個演算法的複雜度是\(o(n)\)的。
2.如何求\(nxt\):
我們發現\(nxt\)的定義和\(exnxt\)的定義十分相像,不過乙個是\(t\)和\(t\)匹配,乙個是\(s\)和\(t\)匹配。
於是我們用同樣的方法就可以求出\(nxt\):暴力算出\(nxt_1,nxt_2\),之後按照1.中的方法求即可。
說來我好像是題解中第二個從1開始數數的。。。不過扶蘇的**太神仙了,我看不懂。
code:
#includeusing namespace std;
const int maxn=100010;
int n,m;
int nxt[maxn],exnxt[maxn];
char s[maxn],t[maxn];
inline void getnxt() }}
inline void getexnxt() }}
int main()
KMP 擴充套件KMP
本文將不斷加入例題,稍安勿躁,今天的總結爭取9 30寫完.kmp,中文名字叫字串匹配,用於解決一類字串匹配問題.先下一些定義 首先我們先想一想 nxt i 對於求解問題有怎樣的幫助.我們對於每乙個 t i s 1 的位置都匹配一次,這樣子複雜度為 theta n m 的.考慮在暴力匹配中其實我們不一...
擴充套件kmp
出自 2 i k l 1 p k,即i l p。這時,首先可以知道a i.p 和b 0.p i 是相等的 因為a i.p b i k.p k 而i k l 1 p k,由b 0.l 1 b i k.i k l 1 可得b 0.p i b i k.p k 即a i.p b 0.p i 然後,對於a p...
擴充套件KMP
拖了這麼久,終於打出擴充套件kmp了。並不長,但是細節很多。最好把模板背下來,實在背不下來就根據原理去推。相比於kmp來說擴充套件kmp的應用範圍更廣,更靈活。它的ext i 與kmp的next i 的區別就是next i 表示長度最大的一段s i next i 1 i t 1 next i ext...