KMP cekmp
例题 HDU 1711 Number Sequence
题目分析 : KMP 模板题
kmp主要 依靠于 next[]数组查找进行优化(前后缀 最长公共子串长度)
如何 优化的呢在查找的时候 在某一处匹配失败时可以直接通过 next[]数组进行跳转
不用重头匹配 简化了查询步骤;
比如 : (ABCAB AABB) ( ABCAB CSDFDS)
当ABCA匹配成功而 ABCA B 匹配失败时 通过next数组就可以
直接跳转到AB(C)位置进行比较
代码如下:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
int ss[1000005],s[10005];//创建数字存储数组
int mo[10005];//next[]数组(最长公共前后缀长度)
int n,m;
int kmp()
{
//next[]数组求值
int j=1,k=0; //j为前缀坐标,k为后缀坐标
mo[1]=0;//一个数字时 最长公共前后缀为0
while(j<=m) //坐标要求不大于最大长度
{
if(k==0||s[j]==s[k])//k=0是空状态 当前后缀一样市
{
j++;//前缀坐标后移
k++;//后缀坐标后移
mo[j]=k;//最长公共前后缀 赋值
}
else
k=mo[k];//如果 不相等 就跳转到 next[] --->缩短路径(可以这么说吧)
}
//比较
int i=1,j=1;//初始比较坐标赋值
while(i<=n)//最大坐标不大于 最长所给
{
if(j==0||ss[i]==s[j])//j=0代表 没有部分前缀相等 //相等就往后移动
{
i++;
j++;
}
else
j=mo[j];//否则就跳转 到next[]
if(j==m+1)//当有匹配最后一个成功时 会出现 j++所以有j==m+1
{
return i-m;//(j++)-m==j-m+1
}
}
return -1;
}
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)//**注意 输入时是从1开始 将0位置空出来了
scanf("%d",&ss[i]);
for(int j=1;j<=m;j++)//**注意 输入时是从1开始 将0位置空出来了
scanf("%d",&s[j]);
cout<<kmp()<<endl;
}
return 0;
}
例题 POJ 1961 Period
解题思路: 就是kmp里的求next数组 然后依次扫一遍看是否出现循环节
AC代码如下:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=1000000+10;
int next[maxn];
string str;
int main()
{
int n;
int ans=0;
while(cin>>n&&n)
{
ans++;
cin>>str;
next[0]=next[1]=0;
for(int i=1;i<n;i++)
{
int j=next[i];
while(j&&str[i]!=str[j])
j=next[j];
next[i+1]=(str[i]==str[j])?j+1:0;
}
cout<<"Test case #"<<ans<<endl;
for(int i=2;i<=n;i++)
{
int len=i-next[i];
if(next[i]>0&&!(i%len))
cout<<i<<" "<<i/len<<endl;
}
cout<<endl;
}
return 0;
}