原理:
随后再写
next数组的求法:
void getnext(){
Next[0]=-1;
int i=0,j=-1,len=strlen(mo);
while(i<len){
if(j==-1||mo[i]==mo[j]){Next[++i]=++j;}
else
j=Next[j];
}
}
匹配过程:
int KMP(){//匹配过程
int i=0,j=0,p=0,l1=strlen(str),l2=strlen(mo);
while(i<l1){
if(j==-1||str[i]==mo[j]){++i,++j;}
else j=Next[j];
if(j==l2)p++;//模式串匹配完了 p用来计数
}
return p;//p统计的是模式串在原串中出现了几次
}
模板:
#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int maxn=1e5;
int Next[maxn];
char str[maxn],mo[maxn];
//求next数组
void getnext(){
Next[0]=-1;
int i=0,j=-1,len=strlen(mo);
while(i<len){
if(j==-1||mo[i]==mo[j]){Next[++i]=++j;}
else
j=Next[j];
}
//打印求出来的next数组的值
// for(int i=0;i<=len;i++)
// printf("%d ",Next[i]);
// printf("\n");
}
//优化后的next数组求法
void getnext1(){
Next[0]=-1;
int i=0,j=-1,len=strlen(mo);
while(i!=len){
if(j==-1||mo[i]==mo[j]){
++i,++j;
if(mo[i]!=mo[j])
Next[i]=j;
else
Next[i]=Next[j];
}
else j=Next[j];
}
//打印求出来的next数组的值
// for(int i=0;i<=len;i++)
// printf("%d ",Next[i]);
// printf("\n");
}
int KMP(){//匹配过程
int i=0,j=0,p=0,l1=strlen(str),l2=strlen(mo);
while(i<l1){
if(j==-1||str[i]==mo[j]){++i,++j;}
else j=Next[j];
if(j==l2)p++;//模式串匹配完了 p用来计数
}
return p;//p统计的是模式串在原串中出现了几次
}
int main(){
gets(str);
gets(mo);
getnext();
printf("%d",KMP());
}
例题 (模板题)(ac代码在文末)
hdu1711 Number Sequence hdu1711
求模式串在原串中第一次出现的位置
hdu2087 剪花布条 hdu2087
求模式串在原串中出现了几次
ps:注意 这类型题目有两种意思
1. 原串 aaaaaa 模式串 aa 出现了 5次
2. 原串 aaaaaa 模式串 aa 出现了 3次(本题是这种情况)
对于不同的情况 要做不同的修改
代码
//hdu1711 求模式串在原串中第一次出现的位置
#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int maxn=1e6+7;
int Next[maxn];
int s[maxn],mo[maxn];
int l1,l2;
void getnext(){
Next[0]=-1;
int i=0,j=-1,len=l2;
while(i<len){
if(j==-1||mo[i]==mo[j]){Next[++i]=++j;}
else
j=Next[j];
}
}
int KMP(){
int i=0,j=0,p=0;
while(i<l1){
if(j==-1||s[i]==mo[j]){++i,++j;}
else j=Next[j];
if(j==l2)return i-j+1;
}
return -1;
}
int T,n,m;
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%d",&s[i]);
for(int i=0;i<m;i++)scanf("%d",&mo[i]);
l1=n;l2=m;
getnext();
printf("%d\n",KMP());
}
}
//hdu2087 模式串在原串中出现几次
#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int maxn=1e6+7;
int Next[maxn];
char s[maxn],mo[maxn];
int l1,l2;
void getnext(){
Next[0]=-1;
int i=0,j=-1,len=l2;
while(i<len){
if(j==-1||mo[i]==mo[j]){Next[++i]=++j;}
else j=Next[j];
}
}
int KMP(){
int i=0,j=0,p=0;
while(i<l1){
if(j==-1||s[i]==mo[j]){++i,++j;}
else j=Next[j];
if(j==l2)p++,j=0;//出现一次 模式串就要回到初始位置
}
return p;
}
int T,n,m;
int main(){
while(~scanf("%s",s)){
if(s[0]=='#')return 0;
scanf("%s",mo);
l1=strlen(s);l2=strlen(mo);
getnext();
printf("%d\n",KMP());
}
}