【模板】KMP算法、fail树
ACM模板
目錄
- KMP字符串
- Fail失配樹
KMP字符串
肖然大佬視頻講解
子串: 從原串中選取連續的一段,即為子串(包括空串)
前綴: pre(s,k)pre(s,k)pre(s,k) 為 s 前 k 個字符構成的子串
后綴: suf(s,k)suf(s,k)suf(s,k) 為 s(k…n) 構成的子串
任何子串都是某個后綴的前綴
最長公共前綴 lcp(s,t)lcp(s,t)lcp(s,t) 和最長公共后綴 lcs(s,t)lcs(s,t)lcs(s,t)
周期: ①0<p<∣s∣0<p<|s|0<p<∣s∣ ②s[i]=s[i+p],?i∈{1,2,…,∣s∣?p}s[i]=s[i+p], \forall i\in\{1,2,\dots,|s|-p\}s[i]=s[i+p],?i∈{1,2,…,∣s∣?p},滿足以上條件,稱 ppp為 s 的周期
Border: ①0<r<∣s∣0<r<|s|0<r<∣s∣ ②pre(s,r)=suf(s,r)pre(s,r)=suf(s,r)pre(s,r)=suf(s,r),滿足以上條件,稱 pre(s,r)pre(s,r)pre(s,r)為 s 的 border
周期與Border的關系:pre(s,k)pre(s,k)pre(s,k)是 s 的 border ?\Leftrightarrow? ∣s∣?k|s|-k∣s∣?k 是 s 的周期
Border的傳遞性:
①串 s 是 t 的 border ,串 t 是 r 的 border,那么 s 是 r 的border
②串 s 是 r 的 border,串 t (∣t∣>∣s∣|t|>|s|∣t∣>∣s∣)也是 r 的 border,則 s 是 t 的border
記 mb(s) 表示 s 的最長 border 則 mb(s),mb(mb(s))…構成 s 的所有 border
給定一個模式串S,以及一個模板串P,所有字符串中只包含大小寫英文字母以及阿拉伯數字。
模板串P在模式串S中多次作為子串出現。
求出模板串P在模式串S中所有出現的位置的起始下標(0開始)。
#include<iostream> using namespace std; const int N=1000010; int n,m; char p[N],s[N]; int ne[N]; int main() {cin>>n>>p+1>>m>>s+1;// 求ne過程看成兩個相同的串匹配for(int i=2,j=0;i<=n;i++){while(j&&p[i]!=p[j+1]) j=ne[j];if(p[i]==p[j+1]) j++;// i結尾能夠匹配 1~j 那么ne[i]=jne[i]=j;}// 當前需要判斷是否匹配 p[j+1]?=s[i]for(int i=1,j=0;i<=m;i++){while(j&&s[i]!=p[j+1]) j=ne[j];if(s[i]==p[j+1]) j++;if(j==n){cout<<i-n<<' ';j=ne[j];}}return 0; }Fail失配樹
概念以及構造: 將 next[i] 視為 i 點的父節點,那么通過 next 數組可以把 0~N 點連成一棵樹,滿足性質:
- 點 i 的所有祖先都是前綴 pre(s,i) 的 border
- 沒有祖先關系的兩個點 i,j 沒有 border 關系
聯系: 計算 next[i] 的過程可以看作:從 j=fa[i-1] 開始不斷往上走,找到第一個滿足 s[j+1]=s[i] 的點,把點 i 的父親設為 j+1
#include<string> #include<iostream> using namespace std; const int N=1000010; int ne[N]; int fa[N][21],dep[N]; string s; int n; int lca(int a,int b) {if(dep[a]<dep[b]) swap(a,b);for(int k=20;k>=0;k--)if(dep[fa[a][k]]>=dep[b]) a=fa[a][k];if(a==b) return a;for(int k=20;k>=0;k--)if(fa[a][k]!=fa[b][k]){a=fa[a][k];b=fa[b][k];}return fa[a][0]; } int main() {cin>>s;n=s.size();s="."+s;dep[0]=1,dep[1]=2;fa[1][0]=0;for(int i=2,j=0;i<=n;i++){while(j&&s[i]!=s[j+1]) j=ne[j];if(s[i]==s[j+1]) j++;ne[i]=j;// 構建失配樹fa[i][0]=j;dep[i]=dep[j]+1;for(int k=1;k<=20;k++)fa[i][k]=fa[fa[i][k-1]][k-1];}int q;cin>>q;while(q--){int a,b;cin>>a>>b;int pab=lca(a,b);// 注意本身是公共祖先的情況if(a==pab||b==pab) cout<<ne[pab]<<'\n';else cout<<pab<<'\n';}return 0; }總結
以上是生活随笔為你收集整理的【模板】KMP算法、fail树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 咏史的诗句 诗句盘点
- 下一篇: 那达慕是哪个民族的节日风俗 那达慕大会有