字串匹配---KMP
阿新 • • 發佈:2018-12-20
原理:
隨後再寫
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());
}
}