题目
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数组的思想十分重要。
next[i]的值为使P[0…i]这个子串的K-真前缀等于K-真后缀的最大的K
代码
#include <iostream>
#include <cstring>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 10005;
const int maxm = 1000005;
int Next[maxn], res, n;
char p[maxn], s[maxm];
void get_next(const char ptr[],int len)
{
Next[0] = 0;
for (int i = 1, j = 0; i < len; i++)
{
while (j&&ptr[j] != ptr[i])
j = Next[j - 1];
if (ptr[j] == ptr[i])
j++;
Next[i] = j;
}
}
void KMP(const char str[],const char ptr[])
{
int len1 = strlen(str), len2 = strlen(ptr), j = 0;
get_next(ptr, len2);
for (int i = 0; i < len1; i++)
{
while (j&&ptr[j] != str[i])
j = Next[j - 1];
if (ptr[j] == str[i])
j++;
if (j == len2)
{
res++;
j = Next[j - 1];
}
}
}
int main()
{
scanf("%d", &n);
while (n--)
{
memset(p, 0, sizeof(p));
memset(s, 0, sizeof(s));
memset(Next, 0, sizeof(Next));
res = 0;
scanf("%s", p);
scanf("%s", s);
KMP(s, p);
printf("%d\n", res);
}
return 0;
}