KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。
问题:求a字符串与b字符串中子串相同的串首位置。
暴力就不说了,设a长m,b长n,每次枚举比对每个字符,复杂度O(nm)。
KMP主要思想:如果一个字符串的子串与前缀相等,那么在查找时就可以直接将前缀跳至该子串的位置。复杂度O(n)。
nxt[x]记录x位置字符在查询串中的跳转位置。
eg:对于串abaabacac:
a b a a b a c a c
-1 0 0 1 1 2 3 0 1
inline void getnxt() { int j=0,k=-1; nxt[0]=-1; while(j<s.length()-1) { if(k==-1||s[j]==s[k])nxt[++j]=++k; else k=nxt[k]; } }
查询时跳转即可。
模拟一下就知道啦~
全代码:
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; string s,t; int nxt[1000]; inline void getnxt() { int j=0,k=-1; nxt[0]=-1; while(j<s.length()-1) { if(k==-1||s[j]==s[k])nxt[++j]=++k; else k=nxt[k]; } } inline int indexkmp() { int i=0,j=0; while(i<s.length() and j<t.length())//如果比完了就退出来了 if(i==-1 or s[i]==t[j])i++,j++; else i=nxt[i]; if(i>=s.length())return j-s.length(); return -1; } int main() { std::ios::sync_with_stdio(false); cin>>s>>t; getnxt(); cout<<indexkmp()+1; return 0; }
例题
#include<iostream> #include<cstdio> #include<string> #include<cstring> using namespace std; const int maxn=1e6+5; int nxt[maxn]; char a[maxn],b[maxn]; int lena,lenb; inline void getnxt() { int k=-1,j=0; nxt[0]=-1; while(j<lena) if(k==-1 or a[k]==a[j]) nxt[++j]=++k; else k=nxt[k]; } inline void indexkmp() { int j=0,i=0; while(j<lena and i<lenb) if(j==-1 or a[j]==b[i]){ i++,j++; if(j==lena){ printf("%d ",i-lena+1); j=nxt[j]; } } else j=nxt[j]; } int main() { scanf("%s %s",&b,&a); lena=strlen(a); lenb=strlen(b); getnxt(); indexkmp(); for(int i=1;i<=lena;i++) printf("%d ",nxt[i]); return 0; }