问题描述
ZJM 的女朋友是一个书法家,喜欢写一些好看的英文书法。有一天 ZJM 拿到了她写的纸条,纸条上的字暗示了 ZJM 的女朋友 想给 ZJM 送生日礼物。ZJM 想知道自己收到的礼物是不是就是她送的,于是想看看自己收到的礼物在纸条中出现了多少次。
Input
第一行输入一个整数代表数据的组数
每组数据第一行一个字符串 P 代表 ZJM 想要的礼物, 包含英语字符 {‘A’, ‘B’, ‘C’, …, ‘Z’}, 并且字符串长度满足 1 ≤ |P| ≤ 10,000 (|P| 代表字符串 P 的长度).
接下来一行一个字符串 S 代表 ZJM 女朋友的纸条, 也包含英语字符 {‘A’, ‘B’, ‘C’, …, ‘Z’}, 满足 |P| ≤ |S| ≤ 1,000,000.
Output
输出一行一个整数代表 P 在 S中出现的次数.
Sample input
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
Sample output
1
3
0
解题思路
这个题是一道字符串匹配问题,因此我们可以用到KMP算法,这是一道经典的字符串匹配算法,其中next数组的思想十分重要(AC自动机中也用到了这个数组)。KMP讲解可以看一下这个链接。
KMP的时间复杂度可以达到。我用Sunday算法尝试了一下这个题,结果TLE了,不知道是数据卡Sunday还是我自己改Sunday改错了。Sunday有点不稳定,平均复杂度,最坏。有兴趣的可以看一下这个博客。
完整代码
//#pragma GCC optimize(2)
//#pragma G++ optimize(2)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int maxn=10000+10;
const int maxm=1000000+10;
int nxt[maxn],ans,n;
char ptr[maxn],str[maxm];
void get_next(const char ptr[],int len){
nxt[0]=0;
for (int i=1,j=0; i<len; i++){
while(j && ptr[j]!=ptr[i]) j=nxt[j-1];
if(ptr[j]==ptr[i]) j++;
nxt[i]=j;
}
}
int kmp(const char str[],const char ptr[]){
int len1=strlen(str);
int len2=strlen(ptr);
int j=0;
get_next(ptr,len2);
for (int i=0; i<len1; i++){
while(j && ptr[j]!=str[i]) j=nxt[j-1];
if(ptr[j]==str[i]) j++;
if(j==len2){
ans++;
j=nxt[j-1];
}
}
return ans;
}
int getint(){
int x=0,s=1; char ch=' ';
while(ch<'0' || ch>'9'){ ch=getchar(); if(ch=='-') s=-1;}
while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar();}
return x*s;
}
int main(){
//ios::sync_with_stdio(false);
//cin.tie(0);
scanf("%d",&n);
while(n--){
memset(ptr,0,sizeof(ptr));
memset(str,0,sizeof(str));
memset(nxt,0,sizeof(nxt));
ans=0;
scanf("%s",ptr);
scanf("%s",str);
printf("%d\n",kmp(str,ptr));
}
return 0;
}