擴充套件KMP

2022-05-07 20:18:12 字數 1979 閱讀 4449

這個演算法主要靠畫圖理解,於是學習的時候畫了不少圖,正好寫篇部落格。

擴充套件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...