//这代码是我网上抄来的,我大概讲解一下算法精髓好了
//题目在这 //(本人写的kmp卡了四十秒才卡出正确答案) #include<cstdio> #include<cstring> #include<iostream> using namespace std; //我们的目的是为了在a字符串中寻找b出现的次数 char a[1000100],b[10010]; //la为a的长度,lb为b的长度,cnt为出现的次数(cnt每次都要更新) int la,lb,f[10010],cnt; //麻烦从主函数看起,这是好习惯 //下面就是kmp算法的匹配值函数了(大概就是你们在各大博客看到的Next数组) void k_mp() { //以下尤为重要,建议大家一个字一个字看过去 /*这个函数是用来算出f数组,也就是匹配值数组, 而匹配值数组经过我的研究是这样子的:在第i位 寻找1至i中后缀和前缀相等的位数,接下来讲讲什 么是后缀以及前缀: 先输入b:a b b a b b d e a 匹配值f: 0 0 0 1 2 3 0 0 1 前三个先不说, 看第四个f值为1,为什么为1,因为从1到4之间的字符,开头只有1个与最后1个相等,即a=a; 而第五个为什么为2,因为1到5之间,前面2个与后面2个相同,即ab=ab; 那么第六个为3就是因为1到6的字符中,前三个字符和后三个字符相等,即abb=abb; 第七个为0是因为1至7之间没有开头和结尾相同的字符, 这样应该就会懂得f数组怎么来了吧 而f数组的作用就是,当找到一个不匹配的字符,例如 在i=5的地方(b字符的位置)不匹配的时候,我们不必 回溯到0开始,只需从f[i-1]的地方(f[4]=1)接着匹 配即可这样j也不用回溯了,就节省了大把的时间; */ //此处先更新cnt=0; cnt=0; //len是用来有几位相等的字符 int len=0,i=1; //开头第一个应该定义为0(说实话,我也不知道为什么) f[0] = 0; while(i<lb) { //len是用来记录前面已经有多少个字符相等了 if(b[i]==b[len]) { //如果又相等了一个,len++ len++; //然后f[i]=len;i++,计算下一个 f[i]=len; i++; } //下面这一段我自己也不是很懂 else { if(len!=0) len=f[len-1]; else { f[i] = 0; i++; } } } /* 这个留给你们看f数组好了 for(int i=0;i<lb;i++) cout<<f[i]<<' '; cout<<endl; */ } void KMP() { //la,lb算出来以后,就去做匹配值工作了 la=strlen(a); lb=strlen(b); //匹配值计算开始(这是最虐心的部分) k_mp(); int i=0,j=0; while(i<la) { //如果相等的话就两个都加1 if(b[j]==a[i]) { j++; i++; } //当j==lb说明b串匹配到了 if(j==lb) { //就记录下来一个 cnt++; //可以用printf("第%d个匹配的位置在:%d ",cnt,i-j+1)知道从哪里开始匹配的 //如果要继续查找,那么f数组就派上用场了 j=f[j-1]; } else if(b[j]!=a[i]) { //每次有不匹配的时候,就追溯到f[j-1]的位置 if(j!=0) j=f[j-1]; //当然如果j=0就不用了,直接匹配下一位就行,即i++ else i++; } } //这样这一题就搞定了,希望你们能看得懂此题解 } //咱们先看主函数 int main() { int n; //输入要输入的组数n,表示有n组数据 scanf("%d",&n); while(n--) { //先输入b,再输入a scanf("%s%s",b,a); //然后用Kmp算法算出b在a中出现的次数 KMP(); //输出答案 printf("%d ",cnt); } return 0; }