Description
独眼贝斯基是一个非常喜欢学习但却爱钻牛角尖的怪兽,最近他捡到了一张写着长长的、长长的、长长的密码串S的纸张。正常情况下,他该学习一下怎去破解这密码,但此时那爱钻牛角尖的劲上来了,他想知道自己的手机密码串X在S串上出现了多少次?
Input
第一行一个整数n,表示测试数据组数。
接下来的n*2行,每2行表示一组测试数据。在每一组测试数据中,第一行为手机密码串X,由不超过10^4个字母组成,第二行为S串,由不超过10^6个字母组成(不区分大小写)。
其中n<=20.
Output
对于每一个测试数据,按照它们在输入中出现的顺序输出一行ans,表示X串在S串中出现的次数.
Sample Input
2
HA
HAHAHA
WqN
WQN
Sample Output
3
1
无脑暴力行不通, 特地去学了KMP
kmp + 优化, 开销400ms, 精益求精吧
#include <iostream>
#include <cstring>
#include <cstdio>
int reqs, lenTarget, lenPattern, next[10000 + 10];
char pattern[10000 + 10], target[1000000 + 10];
void BuildNext() {
int i = 0, j = next[0] = -1;
while (i < lenPattern) {
if (j == -1 || pattern[i] == pattern[j]) {
++i; ++j;
if (pattern[i] != pattern[j]) {
next[i] = j;
} else {
next[i] = next[j];
}
} else {
j = next[j];
}
}
}
int Kmp() {
BuildNext();
int cnt = 0, i = 0, j = 0;
while (i < lenTarget) {
if (j == -1 || target[i] == pattern[j]) {
++i; ++j;
} else {
j = next[j];
}
if (j == lenPattern) { ++cnt; }
}
return cnt;
}
void ToLowerLetter(char str[], int len) {
for (int i = 0; i < len; ++i) {
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] = str[i] - 'A' + 'a';
}
}
}
int main() {
scanf("%d%*c", &reqs);
while (reqs--) {
gets(pattern);
gets(target);
lenPattern = strlen(pattern);
lenTarget = strlen(target);
ToLowerLetter(pattern, 10000 + 10);
ToLowerLetter(target, 1000000 + 10);
printf("%d\n", Kmp());
}
return 0;
}
2017.2更优雅版KMP
const int maxn = 1e6 + 10;
char S[maxn], T[maxn];
int fail[maxn];
void BuildFail() {
fail[0] = fail[1] = 0;
for (int i = 1; S[i]; ++i) {
int j = fail[i];
if (S[fail[i]] == S[i]) //小优化,但不降低复杂度
fail[i] = fail[fail[i]];
while (j && S[i] != S[j]) j = fail[j];
fail[i + 1] = S[i] == S[j] ? j + 1 : j;
}
}
int Query() {
int j = 0, ans = 0;
for (int i = 0; T[i]; ++i) {
while (j && S[j] != T[i]) j = fail[j];
if (S[j] == T[i]) ++j;
if (!S[j]) ++ans;
}
return ans;
}