【笔记】好背的KMP

首先,KMP的原理请自行百度,不再赘述。

来个好背的代码好了,给我背了半年的这个算法收个尾(

首先,把KMP想象成一个图(或者叫自动机?),可以实现每次给一个字符和一个当前状态,跳到下一个状态。

好,这就是这种写法的精髓了(

上一下跳状态的代码:

//state:当前状态
//c:跳的依据
//ch:模式串
int go(int state,char c){
      while(1){
            if(ch[state]==c)return state+1;
            if(!state)return 0;
            state=fail[state];
      }
}//其实递归更好背但是容易爆栈=w=
//可以记忆化搜索优化,有的题有用

然后接着几部分直接背也没啥的了(

void build() {
      for(int i=1;ch[i+1];++i)fail[i+1]=go(fail[i],ch[i]);
      //ch[i+1]解释:i+1位还有字符(也就是没超边界)
      //要是i+1超边界了,fail[i+1]也就不会被用到了
}
void run(){
      for(int i=0,u=0;tom[i];++i){
            u=go(u,tom[i]);
            //此时u记录的是模式串匹配到了哪一位,接下来比如可以这样:
            if(!ch[u]){
                  //匹配上了,做些处理
            }
      }
}

最后上个板子代码:输入两个字符串a,b,求b在a中出现的次数和位置。

一行a一行b。

#include<bits/stdc++.h>
using namespace std;
char tom[10000009];
char ch[10000009];
int fail[10000009];
int go(int state,char c){
  	while(1){
      	if(ch[state]==c)return state+1;
      	if(!state)return 0;
      	state=fail[state];
    }
}
void build() {
      for(int i=1;ch[i+1];++i)fail[i+1]=go(fail[i],ch[i]);
}
void run(){
      for(int i=0,u=0;tom[i];++i){
            u=go(u,tom[i]);
            if(!ch[u+1]){//最后一位失配,详见主函数处理
                  printf("%d\n",i-u+2),u=fail[u];
            }
      }
}
int main(){
      freopen("pattern.in","r",stdin);
      freopen("pattern.out","w",stdout);
      cin>>tom;tom[strlen(tom)]='#';
      cin>>ch;ch[strlen(ch)]='%';
      build();
      run();
      return 0;
}

应该是对的吧(

Over.

posted @ 2020-09-16 22:46  UnyieldingTrilobite  阅读(262)  评论(4编辑  收藏  举报