【笔记】好背的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.