题意:
给定一个文本串s和一个模式串p,找出模式串在文本串中出现的次数。注意:模式串在文本串中出现的位置不能重叠
当然本题不用kmp算法也能通过,借用本题回忆一下kmp算法。
kmp算法要用到一个数组记录一下信息,此数组取名为next[],现在说一下next数组的含义:
next[i] 表示模式串p的前i个 字符组成的前缀这个字符串的前缀和后缀能匹配的最大值k。(k<i)
解释一下字符串前缀和后缀:
假设字符串string为 a1a2a3.....an(字符串的长度为n)
string的前缀是这样的字符串: a1a2.....ai (1<=i<=n)
string的后缀是这样的字符串: ai..........an (1<=i<=n)
例如 abcabc这个字符串的前缀和后缀能匹配的最大值是3
next数组的作用就是当模式串和文本串匹配到某个位置,在此位置之后的字符不能匹配时,next数组指明了模式串应跳到某个位置继续和文本串继续匹配
根据模式串求next数组的函数
// next[i-1]是字符串a1a2....a(i-1)的前缀和后缀匹配的最大值,为了方便令 k = next[i-1],如果a(k+1)== a[i],那么next[i] = k+1,否则令k = next[k],继续循环,直到 k==0 或者 p[k+1] == p[i]
void getnext(char* p) //p是模式串
{
next[1] = 0;
int k = 0;
for(int i=2;i<=lenp;i++) //k的值为next[i-1],根据以前求得的next值求next[i]
{
while(k!=0 && p[k+1] != p[i])
k = next[k];
if(p[k+1] == p[i]) k++;
next[i] = k;
}
}
kmp函数
void kmp(char* p, char* s)
{
getnext(p);//求得next数组
int q = 0; //q表示模式串p和文本串s当前匹配的个数,初始化为0
for(int i=1;i<=lens;i++)
{
while(q!=0 && p[q+1] != s[i])
q = next[q];
if(p[q+1] == s[i]) q++;
if(q == lenp)
{
//此时模式串已经在文本串中出现过
}
}
}
hdu2087代码:
#include <cstdio>
#include <cstring>
const int maxn = 1005;
char p[maxn], s[maxn];
int lenp,lens,cnt;
int next[maxn];
void getnext(char* p)
{
next[1] = 0;
int k = 0;
for(int i=2;i<=lenp;i++)
{
while(k!=0 && p[k+1] != p[i])
k = next[k];
if(p[k+1] == p[i]) k++;
next[i] = k;
}
}
void kmp(char* p, char* s)
{
getnext(p);//求得next数组
int q = 0; //q表示模式串p和文本串s当前匹配的个数,初始化为0
for(int i=1;i<=lens;i++)
{
while(q!=0 && p[q+1] != s[i])
q = next[q];
if(p[q+1] == s[i]) q++;
if(q == lenp)
{
cnt++;
q = 0;
}
}
}
int main()
{
while(scanf("%s",s+1)!=EOF && s[1] != '#')
{
scanf("%s",p+1);
lens = strlen(s+1);
lenp = strlen(p+1);
cnt = 0;
kmp(p,s);
printf("%d\n",cnt);
}
return 0;
}