题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087
解题思路:这是KMP算法模板的应用。需要注意的地方就是,这里的子串需要重新取,所以对于j的处理时要改变一下。

版本1

#include <cstdio>
#include <cstring>
#include <cstdlib>
const int maxn = 1010;
int next[maxn];
char str[maxn],pat[maxn];
void getNext(char s[],int len){
	int j=-1;
	next[0]=-1;
	for(int i =1;i<len;i++){
		while(j!=-1&&s[i]!=s[j+1]){
			j=next[j];
		}
	
		if(s[i]==s[j+1]){
		j++;
		}
		next[i]=j;
    }
} 
//统计pattern串在text串中出现的次数
int KMP(char text[],char pattern[]){
	int n=strlen(text);
	int m=strlen(pattern);
	getNext(pattern,m);
	int ans = 0,j=-1;
	for(int i=0;i<n;i++){
		while(j!=-1&&text[i]!=pattern[j+1]){
			j=next[j];
		}
		if(text[i]==pattern[j+1]){
			j++;
		}
		if(j==m-1){
			ans++;
			j=next[0];
		}
	}
	return ans;
} 
int main(){
	while(scanf("%s",str)!=EOF&&str[0]!='#'){
		scanf("%s",pat);
		memset(next,0,sizeof(next));
		int tmp=KMP(str,pat);
    	printf("%d\n",tmp);
	}
	return 0;
}

版本2

根据左神进阶视频讲解改写而成,十分感谢左神,终于让我弄懂了KMP算法。

#include<cstdio>
#include<cstring>
using namespace std;
char str1[1005],str2[1005];
int next[1005];
void getNext(char str[],int len){
	int i=2,cn=0;
	next[0]=-1;
	next[1]=0;
	while(i<len){
		if(str[i-1]==next[cn]) next[i++] = ++cn;
		else if(cn > 0) cn = next[cn];
		else next[i++] = 0;
	}
}
int main(){
	while(scanf("%s",str1)&&str1[0]!='#'){
		scanf("%s",str2);
		int len1 = strlen(str1);
		int len2 = strlen(str2);
		int j=0,i=0,cnt=0;
		getNext(str2,len2);
		while(i<len1){
			if(str1[i] == str2[j]){
				i++; 
				j++;
			}else{ //甲乙没配上,则乙往右推 
				if(next[j]==-1){ //推不动了,乙已经在0位置了,则只能让甲移动 
					i++; 
				}else{ //乙还能推,则推到j的最长前缀的下一个位置 
					j = next[j];  
				} 
			}
			if(j == len2){ //说明已经匹配上str2了,但是还要继续找 
				j=0;
				cnt++;
			} 
		}
		printf("%d\n",cnt);
	}
	return 0;
}