kmp这东西还是蛮强的,能在线性的时间完成字符串匹配,相比wo我之前会的都是o(n2)的 快的不是一点半点,下面简单说下kmp的原理
现在我们有母串s,模式串t;
我们传统的字符串匹配都思想是,不管此次匹配成功与否,都是模式串向前移动一位继续匹配,这样子效率肯定是很慢的,因为我们根本没有利用到之前已经匹配过的信息
kmp算法就是利用之前匹配的信息,使模式串前移更多的位,使其效率大大提升,那么我们怎么知道什么时候前移多少位呢,首先我们假设现在模式串第j位与母串第i位匹配成功
,接下来就是匹配s[i+1]和t[j+1]如果s[i+1]!=t[j+1]那么按照我们传统的匹配方法我们这时j变为0,从头继续开始匹配,kmp,改进的就是这里,实际上不用,只用找到,前面匹配过的前缀等于后缀的最大长度即可,那么我们怎找到这个前缀等于后缀的最大长度呢(其实我觉的这个才是kmp最难的)我们可以通过预处理的方法求出,开一个next数组表长度
为i的字符串的前缀等于后缀的最大长度是多少,为什么要这样定义呢,因为字符串下标是从0开始的,这样的话每次找到最大长度d后那么t【d】代表的是最大长度后面的字符,就很方便,然后我们怎么去找出每个位置的最大长度呢,我们可以发现下一位的最大长度只跟上一次的有关,那么我们可以用一个变量记录上一次的的最大长度,然后跟第i位比较就行了(这里说的有点不清楚,请看代码);
参考博文:http://www.cnblogs.com/kuangbin/archive/2012/08/14/2638803.html
http://www.matrix67.com/blog/archives/115
kmp模版:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<iostream>
#include<sstream>
#define LL long long
using namespace std;
const int maxn = 1e5;
char s[maxn];
char t[maxn];
int lens;
int lent;
int next[maxn];
void getNext()
{
int j = 0 ;
int k = -1;
next[0] = -1;
while(j<lent)
{
if(k==-1||t[j]==t[k])
{
next[++j] = ++k;
}
else
k = next[k];
}
}
int kmp()
{
getNext();
int ans = 0;
int k = 0;
for(int i = 0 ; i<lens;i++)
{
while(k>0&&s[i]!=t[k])
{
k = next[k];
}
if(s[i] == t[k])
{
k++;
}
if(k == lent)
{
ans++;
}
}
return ans;
}
int main()
{
while(~scanf("%s%s",s,t))
{
lens = strlen(s);
lent = strlen(t);
cout<<kmp()<<endl;
}
}
下面是两到模版提:
poj3461
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<iostream>
#include<sstream>
using namespace std;
const int maxn = 1e6+50;
char s[maxn];
char t[maxn];
int Next[maxn];
int n,m;
int lens;
int lent;
int getNext()
{
int j=0;
int k = -1;
Next[0] = -1;
while(j<lent)
{
if(k==-1||t[j]==t[k])
{
Next[++j] = ++k;
}
else
k = Next[k];
}
return 0;
}
int kmp()
{
int k = 0;
getNext();
int ok = 0;
int ans = 0;
for(int i = 0 ;i<lens;i++)
{
while(k>0&&s[i]!=t[k])
{
k = Next[k];
}
if(s[i] == t[k])
{
k++;
}
if(k==lent)
{
ans++;
}
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",t);
scanf("%s",s);
lens = strlen(s);
lent = strlen(t);
printf("%d\n",kmp());
}
}
hdu1711
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<iostream>
#include<sstream>
using namespace std;
const int maxn = 1e6+50;
int a[maxn];
int b[maxn];
int Next[maxn];
int n,m;
int getNext()
{
int j=0;
int k = -1;
Next[0] = -1;
while(j<m)
{
if(k==-1||b[j]==b[k])
{
Next[++j] = ++k;
}
else
k = Next[k];
}
return 0;
}
int kmp()
{
int k = 0;
getNext();
int ok = 0;
for(int i = 0 ;i<n;i++)
{
while(k>0&&a[i]!=b[k])
{
k = Next[k];
}
if(a[i] == b[k])
{
k++;
}
if(k==m)
{
cout<<i+1-m+1<<endl;
ok = 1;
return 0;
}
}
if(!ok)
puts("-1");
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{scanf("%d%d",&n,&m);
for(int i = 0 ;i<n;i++)
{
scanf("%d",&a[i]);
}
for(int i = 0 ;i<m;i++)
{
scanf("%d",&b[i]);
}
if(n<m)
puts("-1");
else
{
kmp();
}
}
}