先推荐个很好的博客,我对KMP的理解是基于这篇博客的。
KMP是用来求串的最大匹配。
KMP是通过对模式串的处理,获得前i个字符的相同的最大前缀和最大后缀。如果前缀与后缀一样,那么匹配会达到这种效果:
这样前面匹配的得到的子串在后续匹配中仍能使用,这时我们只需要for循环目标串,如果比较到不匹配的地方,模式串直接偏移相对应的最大前缀部分,达到了n + m的效果。光看着肯定蒙,用笔模拟过程才是硬道理。
题意就是先给一个T,表示T组数据,然后每一组输入一个str1, str2。str2里能匹配多少个str1.
include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <string.h>
using namespace std;
string s1, s2;
int Next[10005]; //用来处理前i个字符相同的最大前缀和最大后缀,-1表示没有, 0, 表示一个,以此类推。
int ans;
void getnext() //处理模式串,得到NEXT【i】。
{
int k = -1;
Next[0] = -1;
int len = s1.length();
for(int i = 1; i < len; i++)
{
while(k != -1 && s1[i] != s1[k + 1]) //这一步可以说是kmp里最难理解的,其实就是如果他们前i个有相同的前缀和后缀,
{ //但是此时的字符又不匹配,怎么办,我们可以从之前匹配的再找,比如序列32231
k = Next[k]; //next[3] = 0; 那么接下来是2 和 1比较,发现不相等,怎么办,我们可以找前k个的,因为
} //如果k != -1,那么前k个字符前面和后面都有next【k】个相等,相对应的后k个字符也一样,
if(s1[i] == s1[k + 1]) //相当于在i的范围内可以划成四个部分1 2 3 4, 12 = 34, 1 = 2, 所以1 = 4.所以继续比较。
{
k += 1;
}
Next[i] = k;
}
}
void kmp()
{
int k = -1;
int len1 = s1.length();
int len2 = s2.length();
for(int i = 0; i < len2; i++)
{
while(k != -1 && s2[i] != s1[k + 1]) //思想同上,不过这个只需要计数就好
{
k = Next[k];
}
if(s2[i] == s1[k + 1])
{
k += 1;
}
if(k == len1 - 1)
{
ans += 1;
}
}
}
int main()
{
int T;
cin >> T;
while(T--)
{
ans = 0;
memset(Next, -1, sizeof(Next));
cin >> s1 >> s2;
getnext();
kmp();
cout << ans << endl;
}
return 0;
}