博客推荐:
http://www.cnblogs.com/c-cloud/p/3224788.html
http://www.61mon.com/index.php/archives/183/
KMP未优化模版:
//未优化的KMP,可以解决有重复的问题
void getNext(const char *num, int Next[])
{
int i=0,j=-1;
Next[0]=-1;
while(i!=len)
{
if(j==-1||num[i]==num[j])
{
++i,++j;
Next[i]=j;
}
else
j=Next[j];
}
}
KMP优化模版:
//比未优化的更快,但是无法解决重复的问题
void getNext(const int *num2, int nextval[])
{
int i=0,j=-1;
nextval[0]=-1;
while(i!=len2)
{
if(j==-1||num2[i]==num2[j])
{
++i,++j;
if(num2[i]!=num2[j])
nextval[i]=j;
else
nextval[i]=nextval[j];
}
else
j=nextval[j];
}
}
例题:
1.HDU 1711
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define inf 0x3f3f3f3
#define met(a,b) memset(a,b,sizeof(a))
const int maxn = 1e6+10;
int num1[maxn],num2[maxn];
int Next[maxn];
int len1,len2;
void getNext(const int *num2, int Next[])
{
int i=0,j=-1;
Next[0]=-1;
while(i!=len2)
{
if(j==-1||num2[i]==num2[j])
{
++i,++j;
if(num2[i]!=num2[j])
Next[i]=j;
else
Next[i]=Next[j];
}
else
j=Next[j];
}
}
int KMP(int *num1,int *num2,int Next[])
{
int i=0,j=0;
while(i!=len1&&j!=len2)
{
if(num1[i]==num2[j])
++i, ++j;
else
{
if(Next[j]==-1)
++i,j=0;
else
j=Next[j];
}
}
if(j==len2) //返回从主串第几个元素开始匹配
return i-j;
else
return -1;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d",&num1[i]);
for(int i=0;i<m;i++)
scanf("%d",&num2[i]);
len1=n;
len2=m;
getNext(num2,Next);
int pos=KMP(num1,num2,Next);
printf("%d\n",pos==-1?pos:pos+1);
}
}
2.PKU 3461
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define inf 0x3f3f3f3
#define met(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const int maxn = 1e6+10;
char num1[maxn],num2[maxn];
int Next[maxn];
ll len1,len2;
void getNext(const char *num2, int Next[])
{
int i=0,j=-1;
Next[0]=-1;
while(i!=len2)
{
if(j==-1||num2[i]==num2[j])
{
++i,++j;
if(num2[i]!=num2[j])
Next[i]=j;
else
Next[i]=Next[j];
}
else
j=Next[j];
}
}
int KMP(char *num1,char *num2,int Next[])
{
int i=0,j=0;
int count=0;
while(i!=len1&&j!=len2)
{
if(num1[i]==num2[j]||j==-1)
++i, ++j;
else
j=Next[j];
if(j==len2)
{
count++;
j=Next[j];
// 已经完成了一次匹配,直接用Next数组跳转到下一个的位置
}
}
return count;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s%s",num2,num1);
len1=strlen(num1);
len2=strlen(num2);
getNext(num2,Next);
printf("%d\n",KMP(num1,num2,Next));
}
}
3.PKU 2752
代码:
#include <set>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define inf 0x3f3f3f3
#define met(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const int maxn = 4e5+10;
int Next[maxn],ans[maxn];
char num[maxn];
ll len;
//未优化的KMP,可以解决有重复的问题
void getNext(const char *num, int Next[])
{
int i=0,j=-1;
Next[0]=-1;
while(i!=len)
{
if(j==-1||num[i]==num[j])
{
++i,++j;
Next[i]=j;
}
else
j=Next[j];
}
}
int main()
{
while(scanf("%s",num)!=EOF)
{
len=strlen(num);
met(Next,0);
getNext(num,Next);
ll i=len;
int l=0;
ans[l++]=len;
while(Next[i]>0)
{
ans[l++]=Next[i];
// 根据KMP的思想,在长度为Len的位置,去寻找最大的真前后缀匹配
i=Next[i];
}
for(int i=l-1;i>=0;i--)
{
if(i!=0)
printf("%d ",ans[i]);
else
printf("%d\n",ans[i]);
}
}
}