本题主要涉及到kmp算法中的匹配问题,查阅严版数据结构书中p80可知该算法分为两步:
1.对需要查找的字段Strb生成相关next数组,next数组表示当前字符i不匹配时,不回溯,而从Strb的next[i]位置开始匹配。next数组是反映须查找字段strb本身的特性,与待查找文本stra无关。
附上next数组求法:(strb为查找目标字段,stra为需要查找strb字段的文本)
1.next数组前1,2位一定是0,1;
2.第三位开始,设当前位为j,令k=next[j-1]
3.比较strb[j-1]与strb[k]是否相等。如果相等,那么next[j]=K+1,否则,k=next[k]。
4.若k=0,则next[j]=1,若k不等于0则跳转第3步直到k=0或strb[j-1]与strb[k]相等为止。
可能有些同学查阅相关文章发现有的next数组前两位是从-1,0开始的,这是由于数组下标定义的不同,如上方法定义数组下标从1开始,而从-1,0开头的next数组下标是从0开始的。
附上-1,0开头的next数组求法:
void get_next(char str[]){
int i=0,j=-1;
next[0]=-1;
while(i<strlen(str)){
if(j==-1||str[i]==str[j]){
i++;
j++;
next[i]=j;
}else{
j=next[j];
}
}
}
2.生成了next数组之后,便是在需要查找的字段stra中匹配目标字段strb了。
int getans(char stra[],char strb[]){//stra为查找文本,strb为目标单词
int i=0;
int j=0;
int ans=0;//段落中目标字符串的个数
while(i<(int)strlen(stra)){
if(j==-1||stra[i]==strb[j]){//如果文本stra已经匹配完就跳出
i++;
j++;//如果相等的话继续匹配下一个。
}else{
j=next[j];//跳到指定位置继续匹配。
}
if(j>=(int)strlen(strb)){//当匹配成功时
ans++;
i=i-strlen(strb)+1;//stra的位置回溯到下一个字符
j=0;//strb从头开始匹配
}
}
return ans;
}
通过这两步就可以用kmp的方式解决这个问题。以下是ac代码
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
char stra[1002];
char strb[1002];
int next[22];
int n;
void get_next(char str[]){
int i=0,j=-1;//int i=1,j=0;
next[0]=-1;
while(i<strlen(str)){
if(j==-1||str[i]==str[j]){
i++;
j++;
next[i]=j;
}else{
j=next[j];
}
}
}
int getans(char stra[],char strb[]){//stra为查找文本,strb为目标单词
int i=0;
int j=0;
int ans=0;
while(i<(int)strlen(stra)){
if(j==-1||stra[i]==strb[j]){
i++;
j++;
}else{
j=next[j];
}
if(j>=(int)strlen(strb)){
ans++;
i=i-strlen(strb)+1;
j=0;
}
}
return ans;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%s%s",strb,stra);
get_next(strb);
int ans=getans(stra,strb);
printf("%d\n",ans);
}
return 0;
}