問題描述
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;
}