擴充套件KMP學習筆記

2022-06-06 08:45:08 字數 2106 閱讀 9364

對於字串\(s\),定義\(z[i]\)為從位置\(i\)開始的\(s\)字尾與\(s\)的最長公共字首的長度。擴充套件\(kmp\)就是用於在\(\mathcal o(n)\)複雜度下求解\(z\)函式的演算法。

既然是擴充套件\(kmp\),那麼當然與\(kmp\)有一定的關係:這一點主要體現在思想上,兩者都在求解的過程中通過之前已經求解的答案來快速計算新的答案(實際上不少字串演算法都利用了這個思想)

假設我們已經求好了\(z[1]-z[i-1]\),現在我們要求解\(z[i]\)。

根據\(z\)函式的性質,我們知道對於任意的\(i\)都有\(s[i,i+z[i]-1]=s[1,z[i]]\),這一點非常有用,於是我們維護最長的形如\([i,i+z[i]-1]\)的匹配段,記為\([l,r]\),特別注意的是\(z[1]\)顯然等於\(|s|\),但它比較特殊,不算作匹配段,於是我們從\(2\)開始列舉\(z\),初始令\(l=r=0\)。

計算\(z[i]\)時,如果\(i\le r\),那麼根據\([l,r]\)的定義就會有\(s[i,r]=s[i-l+1,r-l+1]\),又因為根據\(z[i-l+1]\)的性質

\[s[1,z[i-l+1]]=s[i-l+1,i-l+1+z[i-l+1]-1]

\]於是有

\[s[i-l+1,r-l+1]=s[1,min(z[i-l+1],r-i+1)]

\]因此:\(z[i]\ge min(z[i-l+1],r-i+1)\),我們直接將它作為\(z[i]\)的初始值

然後我們再暴力的增加\(z[i]\)並判斷是否合法,最後用\(z[i]\)來更新\(r\),這就是求解\(z\)函式的過程了。

**如下:

inline void getz(char *s,int n)

}

這個實現過程簡單易懂,但它的複雜度為什麼正確呢?

實際上這裡的複雜度與manacher演算法類似,整個過程中唯一看起來非線性的就是暴力擴充套件\(z[i]\)了,考慮什麼時候我們會暴力擴充套件\(z[i]\):

洛谷模板題

這道題目除了求解\(z\)函式之外,還要我們求解\(s\)的每乙個字尾與\(t\)的\(lcp\),也就是\(p\)陣列,這個過程是類似的。

同樣考慮我們已經求得了\(p[1-i-1]\)求解\(p[i]\),我們同樣維護最長的匹配段\([i,i+p[i]-1]\),記為\([l,r]\),有\(s[l,r]=t[1,r-l+1]\)

那麼同樣的,當\(i\le r\)時,有\(s[i,r]=t[i-l+1,r-l+1]=t[1,min(z[i-l+1],r-i+1)]\),故我們將\(p[i]\)的初始值設為\(min(z[i-l+1],r-i+1)\),然後暴力擴充套件即可。它的複雜度顯然也是線性的:

#includeusing namespace std;

const int n=2e7+10;

typedef long long ll;

char s[n],t[n];

int n,m,p[n],z[n];

inline void getz(char *s,int n)

} inline void exkmp()

}int main()

cf126b password

題目要求我們對於字串\(s\)求出既是\(s\)的字首又是\(s\)的字尾同時又在\(s\)中間出現過的最長子串。

依然求出\(z\)函式,從左到右列舉,當列舉到\(i\)時,如果\(z[i]=n-i+1\),那麼就以為著從\(i\)開始的字尾同時也是\(s\)的乙個字首,判斷它在\(s\)中間出現過也很容易,只需要\(max_^z[i]\ge n-i+1\)即可

#includeusing namespace std;

const int n=1e6+10;

char s[n];

int z[n],n;

inline void getz(char* s,int m)

}int main()

mx=max(mx,z[i]);

} puts("just a legend");

return 0;

}

總結:擴充套件\(kmp\)演算法的應用不太多,核心還是在於它這種利用之前求出的資料加速求解的思想。

擴充套件kmp初學習

參考部落格 問題定義 給出兩個字串s和t 長度分別是n和m 下標從0開始,定義extend i 表示s i s n 1 與t的最長公共字首的長度,求出所有的extend i 如下表i0 1234 567s aaaa abbb taaa aacextend i 54 3210 00如果某個extend...

擴充套件KMP模板(學習)

乙個算是冷門的演算法 在競賽上 不過其演算法思想值得深究。kmp的演算法思想,具體可以參考這篇 trie樹 字典樹 擴充套件kmp的模板問題 給你兩個字串s,t,長度分別為n,m。請輸出s的每乙個字尾與t的最長公共字首。雜湊是不可能的,這輩子都不可能的。mathcalac自動機?好像更不可做了。我們...

KMP 擴充套件KMP

本文將不斷加入例題,稍安勿躁,今天的總結爭取9 30寫完.kmp,中文名字叫字串匹配,用於解決一類字串匹配問題.先下一些定義 首先我們先想一想 nxt i 對於求解問題有怎樣的幫助.我們對於每乙個 t i s 1 的位置都匹配一次,這樣子複雜度為 theta n m 的.考慮在暴力匹配中其實我們不一...