一篇很水的关于KMP的博客

写博客的时候离中午下课还有40+分钟,所以让我先吼一句——肚子好饿啊,下面进入正题,咳咳咳

求一个模式串T在文本串S中出现了多少次

int m=T.length(),n=S.length();

暴搜算法的复杂度最坏的情况下是O(m*n)

辣么,如何减少重复的计算咧/kb

 

暴搜的时候我们一位一位的后移,但其实在一次比较之后,我们已知道几位的匹配情况,这时候就不用一位一位的后移,直接后移多位即可

 

如果当前模式串的T[1…x]已经跟文本串的S[p+1...p+x]完全匹配,但是T[x+1]S[p+1+x]无法匹配。那么此时我们考虑如何运用已有的T[1…x]S[p+1…p+x]完全匹配的信息

 

考虑如果T[1…x]这个字符串,如果某个后缀T[x-k…x],跟前缀T[1…1+k]可以完全匹配,且T[x-k…x]可以和S[p+x-k..p+x]完全匹配,那么此时T[1…1+k]就可以和S[p+x-k…p+x]完全匹配

即T[1...1+k]=T[x-k...x]=S[p+x-k...p+x]

我们只需要找到最长的能跟前缀完全匹配的后缀,这样我们就能在匹配失败(失配)之后,直接将模式串开头移动到S[p+x-k]的位置

 

next[i]表示以i结束的非前缀子串能够匹配的最长的前缀

 

那么只要算出这个next数组就行了

 

考虑在next[1]…next[i-1]都计算出来的情况下如何计算next[i]

如果next[i-1]的下一位能和S[i]匹配,那么

next[i]=next[i-1]+1

如果不能,那么我们需要找到next[next[i-1]]判断他的下一位能否和s[i]匹配。如果还不能,就继续往前找,直到找到0为止

KMP算法  next数组的求法

  1. 初始化next[1]=j=0,假设next[1~i-1]已求出,下面求解next[i]
  2. 不断尝试扩展匹配长度j,如果扩展失败(下一个字符不相等),令j变为next[j],直至j0(再重新从头开始匹配)
  3. 如果能够扩展成功,匹配长度j就增加1next[i]的值就是j

next[1] = 0;

int j=0;

for(int i=2;i<=n;i++)

{

      while(j>0&&(j==n||b[i]!=a[j+1])) j=next[j];

      if(b[i]==a[j+1]) j++;

      f[i]=j;

      //if (f[i]==n) 这就是子串在母串中的某一次出现

}

猜你喜欢

转载自blog.csdn.net/luoyin_2021/article/details/82849763