单模式串匹配----浅谈kmp算法
Posted 15owzly1-yiylcy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单模式串匹配----浅谈kmp算法相关的知识,希望对你有一定的参考价值。
模式串匹配,顾名思义,就是看一个串是否在另一个串中出现,出现了几次,在哪个位置出现;
p.s. 模式串是前者,并且,我们称后一个 (也就是被匹配的串)为文本串;
在这篇博客的代码里,s1均为文本串,s2均为模式串;
一般地,文本串长度不小于匹配串;(否则无意义)
很显然可以得到一个暴力的做法 :
for i : 1~lenth_of_s1 {//枚举匹配串在文本串中的开始位置 for j : 1~lenth_of_s2 if(s2[j]!=s1[i+j-1]) break; if j>lenth_of_s2 //在循环结束前没有break output : i }
时间复杂度:O ( TLE ) ------ O (N+M) ~ O(N*M)
所以需要一个更优的算法;
可以发现,在枚举匹配串在文本串中的开始位置时,有很多步骤是无效的,因为匹配串的第一个字符 很有可能和当前枚举到的开始位置 不同;
所以可以优化这个过程,每次改变开始位置时,直接移动到下一个和匹配串第一个字符相同的位置 (类似于链表;
int next[N], pos=-1; char head = s2[1]; for i : lenth_of_s1~1 if s1[i]==head { next[i] = pos; pos = i; } next[0] = pos; for i = next[0] ; i != -1 ; i = next[i] { for j : 1~lenth_of_s2 if(s2[j]!=s1[i+j-1]) break; if j>lenth_of_s2 //在循环结束前没有break output : i }
这个做法看起来很强,实际上很容易被卡成O (n^2);
比如说 :s1 :sssssssssssssa, s2 : sssb;
由于并没有利用所有已经匹配过的部分,所以仍然会T;
于是,就有了KMP算法。
p.s. i表示当前在文本串中枚举到的位置,j表示模式串中的;
在s1[ i ] != s2 [ j ]时,将 j 移动到一个在 j 之前的位置k 使得 s2[ 1 ]~s2[ k ] 与 s2[ j-k+1 ]~s2[ j ]完全相同,那么时间复杂度就是O (N+M) 的了;
p.s. 因为 i , j 两个指针最多移动N+M次;
给一个写模板的链接 :https://www.luogu.org/problemnew/show/P3375
贴代码 :
// luogu-judger-enable-o2 // 15owzLy1 //luogu3375_kmp.cpp //2018 10 02 17:27:50 #include <cstdio> #include <cstring> typedef long long ll; typedef double db; using namespace std; const int N = 1000005; int next[N], la, lb; char a[N], b[N]; template<typename T>inline void read(T &x_) { x_=0;bool f_=0;char c_=getchar(); while(c_<‘0‘||c_>‘9‘){f_|=(c_==‘-‘);c_=getchar();} while(c_>=‘0‘&&c_<=‘9‘){x_=(x_<<1)+(x_<<3)+(c_^48);c_=getchar();} x_=f_?-x_:x_; } inline void get_next() { int j=0; for(int i=2;i<=lb;i++) { while(j&&b[j+1]!=b[i]) j=next[j]; if(b[j+1]==b[i]) ++j; next[i]=j; } } inline void kmp() { int j=0; for(int i=1;i<=la;i++) { while(j&&a[i]!=b[j+1]) j=next[j]; if(b[j+1]==a[i]) ++j; if(j==lb) printf("%d ", i-j+1); } } int main() { #ifndef ONLINE_JUDGE freopen("luogu3375_kmp.in","r",stdin); freopen("luogu3375_kmp.out","w",stdout); #endif scanf(" %s%s", a+1, b+1); la=strlen(a+1), lb=strlen(b+1); get_next(); kmp(); for(int i=1;i<=lb;i++) printf("%d ", next[i]); puts(""); return 0; }
以上是关于单模式串匹配----浅谈kmp算法的主要内容,如果未能解决你的问题,请参考以下文章