给定一个字符串 text 和一个模式串 pattern,求 pattern 在text 中的出现次数。text 和 pattern 中的字符均为英语大写字母或小写字母。text中不同位置出现的pattern 可重叠。
输入格式:
输入共两行,分别是字符串text 和模式串pattern。
输出格式:
输出一个整数,表示 pattern 在 text 中的出现次数。
输入样例1:
zyzyzyz
zyz
输出样例1:
3
输入样例2:
AABAACAADAABAABA
AABA
输出样例2:
3
数据范围与提示:
1≤text, pattern 的长度 ≤106, text、pattern 仅包含大小写字母。
(有关kmp知识请查看字符串的模式匹配(KMP)算法_Jitwxs-CSDN博客_字符串的模式匹配)
注意:
1.这里对时间卡的很紧,如果使用c++的cin、cout 和string, 即使使用kmp算法照样会超时,
所以要使用char数组和getchar输入
2.km优化版对时间优化作用不大,时间问题出在kmp的比较部分
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char text[1000000], pattern[1000000];
//tlen表示text的长度,plen表示pattern的长度,nt(next)表示pattern的下标
int nt[1000000], tlen=0, plen=0;
//计算pattern的下表nt(next》
void get_next( void ) {
int i=0, j=-1;
nt[0] = -1;
while ( i<plen ) {
if ( j==-1 || pattern[i]==pattern[j] ) {
j ++;
i ++;
nt[i] = j;
} else {
j = nt[j];
}
}
}
//利用kmp算法计算次数
int kmp( void ) {
int cnt=0, i=0, j=0;
while ( i<tlen ) {
while ( i<tlen && j<plen ) {
if ( j==-1 || pattern[j]==text[i] ) {
i ++;
j ++;
} else {
j = nt[j];
}
}
//注意这里是关键,否则照样会超时
//i不能是i-j+1,我刚开始就是这样,照样超时
//这里和前面计算nt(next)的原理一样,把text往前去一个,j变成前一个的下标的那个继续比较
//从而避免重复比较相同部分节省时间
if ( j==plen ) {
cnt ++;
i --;
j = nt[j-1];
}
}
return cnt;
}
int main(void)
{
//使用char,并用getchar输入防止超时
while ( (text[tlen]=getchar())!='\n' ) tlen ++;
while ( (pattern[plen]=getchar())!='\n' ) plen ++;
get_next();
int cnt = kmp();
printf("%d\n", cnt);
return 0;
}