我写这个博客是不是感觉我很牛逼,不不,很菜的,只不过是将思路记下来而已。kmp我是很多都是套模板来A题,对于其中的本质思想,还不是很透彻,所以 给出大佬的博客 :大佬博客
求模式串在待匹配串的出现次数。
Input
第一行是一个数字T,表明测试数据组数。 之后每组数据都有两行:第一行为模式串,长度不大于10000;第二行为待匹配串,长度不大于1000000。所有字符串只由大写字母组成。
Output
每组数据输出一行结果。
Sample Input
4 ABCD ABCD ABA ABABABA CDCDCDC CDC KMP NAIVE
Sample Output
1 3 0 0
来看看这道题目,很明显就是KMP,但是(菜鸡们,我就像一个简单的方法投机取巧,用STL),但是上天惩罚了我,给了我几发TLE,老老实实来看KMP。先亮出我的STL 大法(有人说,我会死在STL上).........
#include<iostream>
#include<cstdio>
#include<map>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
#include<sstream>
#define tle ios::sync_with_stdio(0),cin.tie(0)
using namespace std;
const int maxn=1000005;
typedef long long ll;
typedef pair<int,int> p;
int main()
{
int i,j;
tle;
int t;
cin>>t;
string s1,s2;
while(t--)
{
cin>>s1>>s2;
int ans=0;
size_t found=s2.find(s1);
while(found!=string::npos)
{
ans++;
found=s2.find(s1,found+1);
}
cout<<ans<<endl;
}
return 0;
}
就是这么简单,应该没有算法错误(如果有谢谢各位大佬给我指出来)。
下面看看KMP:
对于这个KMP的详细解法上面大佬博客里面都有,因为也是初学,不能够讲清楚,(抱歉了)。这个题目不是找到一个最先匹配到的下标位置,而是在这个整个文本串里面找一共出现了几次的模式串,相对于模板只是做了简单的改动,在KMP函数中,我们就将这个文本串完全遍历,其他的操作一样,只有有一个匹配成功,就跳到下一个前缀后缀最长的地方,再次进行匹配,直到这个文本串全部遍历完全,就停止,输出几次匹配成功。
while(i<a.length())
{
if(j==-1||a[i]==b[j])
{
i++;
j++;
}
else
{
j=anext[j];
}
if(j==b.length())
{
k++;
j=anext[j];
}
}
只是一些简单的改动,就可以成为另一个题型。路还很长。
#define tle ios::sync_with_stdio(0),cin.tie(0)
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=100005;
string b,a;
int anext[maxn];
void getnext(string s)
{
int i=0,j=-1;
anext[0]=-1;
int len=s.length();
while(i<len)
{
if(j==-1||s[i]==s[j])
{
i++;
j++;
anext[i]=j;
}
else
j=anext[j];
}
}
int kmp(string a,string b)
{
int k=0;
int i=0;
int j=0;
while(i<a.length())
{
if(j==-1||a[i]==b[j])
{
i++;
j++;
}
else
{
j=anext[j];
}
if(j==b.length())
{
k++;
j=anext[j];
}
}
return k;
}
int main()
{
tle;
int i,j;
int t;
cin>>t;
while(t--)
{
memset(anext,0,sizeof(anext));
cin>>b>>a;
getnext(b);
cout<<kmp(a,b)<<endl;
}
return 0;
}