[数据结构]KMP小结
KMP小结
By Wine93 2013.9
1.学习链接: http://www.matrix67.com/blog/archives/115
2.个人小结
1.KMP在字符串中匹配中起着巨大作用,可以在O(n+m)内完成
2.要充分理解next 数组,其求法和next数组的含义(最长后缀等于最长前缀),了解其用途,下面我就next数组在求字符串最小周期中的应用举例
(1).什么是字符串最小周期?
Ex:字符串ababab,最小周期为2,为ab
Ex:字符串abcd,最小周期为4,为abcd
(2)最小周期的一个性质
如果len%(len-next[len])==0,则该字符串的最小周期为len-next[len]
(3)性质的证明
欲证:若len%(len-next[len])==0, 则该字符串的最小周期为len-next[len] (len表示该字符串长度)
证:我们分2部分证
① 若len%(len-next[len])==0,len-next[len]为字符串s的周期
② 证明len-next[len]就是其最小周期
因为next数组的含义是最长后缀等于最长前缀,所以s[ 1……next[len] ]
和s[next[len]+1……len ]是相等的,如上图,线段(1)和线段(2)相等
因为len%(len-next[len])==0,所以我们把线段(2)可以平均分成很多等份(图中假设为4份),每份长度都为s1,线段(1)也可以分成同等份,如上图,根据next数组的定义,s1=s2,又因为s2=s3,而s3=s4….所以依次类推可得s1=s2=s3=s4=s5=s6=s7=s8,所以,s1是字符串s的周期,所以①得证
若len-next[len]不是其最小周期,也就是说存在更小的长度是字符串s的周期,也就是说next[len]要变大(也就是说最长前缀等于最长后缀的值要增大),而根据next数组的定义,next[len]就是已经是最大值(已经是最长前缀等于最长后缀),所以相互矛盾,所以②得证
综上所述: 如果len%(len-next[len])==0,则该字符串的最小周期为len-next[len] (len表示该字符串长度)
3.相关题目:
(1)循环节相关:
POJ 2406 Period http://poj.org/problem?id=2406
# include<cstdio>
# include<cstring>
using namespace std; # define N
int next[N]; void getnext(char *s)
{
int i,j,len=strlen(s);
next[]=j=-;
for(i=;i<len;i++)
{
while(j>=&&s[j+]!=s[i])
j=next[j];
if(s[i]==s[j+])
j++;
next[i]=j;
}
} int main()
{
int i,len;
char s[N];
while(scanf("%s",s)!=EOF&&s[]!='.')
{
getnext(s);
len=strlen(s);
if(next[len-]!=-&&len%(len--next[len-])==)
printf("%d\n",len/(len--next[len-]));
else
printf("1\n");
}
return ;
}
POJ 2406
HDU 3746 Cyclic Nacklacehttp://acm.hdu.edu.cn/showproblem.php?pid=3746
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define N
int Next[N]; void getnext(char *s)
{
int i,j,len=strlen(s);
Next[]=j=-;
for(i=;i<len;i++)
{
while(j>=&&s[j+]!=s[i])
j=Next[j];
if(s[j+]==s[i])
j++;
Next[i]=j;
}
} int main()
{
int T,L,pos,m,d;
char s[N];
scanf("%d",&T);
while(T--)
{
scanf("%s",s);
getnext(s);
L=strlen(s);
if(Next[L-]==-) printf("%d\n",L);
else
{
m=L--Next[L-];
d=Next[L-]+; // (d+x)==0(mod m)
printf("%d\n",(m-d%m)%m);
}
}
return ;
}
HDU 3746
CF 182D Common Divisors http://codeforces.com/problemset/problem/182/D
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define N
int Next[N]; void getnext(char *s)
{
int i,j,len=strlen(s);
Next[]=j=-;
for(i=;i<len;i++)
{
while(j>=&&s[j+]!=s[i])
j=Next[j];
if(s[j+]==s[i])
j++;
Next[i]=j;
}
} int main()
{
int i,len,L1,L2,ans;
char s1[N],s2[N];
while(scanf("%s%s",s1,s2)!=EOF)
{
ans=;
L1=strlen(s1),L2=strlen(s2);
strcat(s1,s2);
getnext(s1);
len=L1+L2;
if(Next[len-]==-||len%(len--Next[len-]))
printf("0\n");
else
{
int m=len--Next[len-];
if(L1%m||L2%m)
printf("0\n");
else
{
for(i=m;i<=L1&&i<=L2;i+=m)
if(L1%i==&&L2%i==)
ans++;
printf("%d\n",ans);
}
}
}
return ;
}
CF 182D
(2)Next数组:
HDU 3336 Count the string http://acm.hdu.edu.cn/showproblem.php?pid=3336
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define MOD
# define N
int Next[N];
int num[N]; void getnext(char *s)
{
int i,j,len=strlen(s);
Next[]=j=-;
for(i=;i<len;i++)
{
while(j>=&&s[j+]!=s[i])
j=Next[j];
if(s[j+]==s[i])
j++;
Next[i]=j;
}
} int main()
{
int T,len,i,ans;
char s[N];
scanf("%d",&T);
while(T--)
{
ans=;
memset(num,,sizeof(num));
scanf("%d%s",&len,s);
getnext(s);
for(i=len-;i>=;i--)
{
num[i]++;
if(num[i]>=MOD)
num[i]-=num[i]/MOD*MOD;
if(Next[i]!=-)
{
num[Next[i]]+=num[i];
if(num[Next[i]]>=MOD)
num[Next[i]]%=MOD;
}
ans=(ans+num[i])%MOD;
}
printf("%d\n",ans);
}
return ;
}
HDU 3336
HDU 2594 Simpsons’ Hidden Talents http://acm.hdu.edu.cn/showproblem.php?pid=2594
# include<cstdio>
# include<cstring>
using namespace std; # define N
char s1[N],s2[N];
int Next[N]; void getnext(char *s)
{
int i,j,len=strlen(s);
Next[]=j=-;
for(i=;i<len;i++)
{
while(j>=&&s[j+]!=s[i])
j=Next[j];
if(s[j+]==s[i])
j++;
Next[i]=j;
}
} int main()
{
int i,L1,L2,pos,ans;
while(scanf("%s%s",s1,s2)!=EOF)
{
L1=strlen(s1),L2=strlen(s2);
strcat(s1,s2);
getnext(s1);
pos=L1+L2-;
/* for(i=0;i<=pos;i++)
printf("%d ",Next[i]);*/
ans=-;
while(pos!=-)
{
if(Next[pos]!=-&&Next[pos]<L1&&L2-(Next[pos]+)>=)
{
ans=Next[pos];
break;
}
pos=Next[pos];
}
if(ans==-) printf("0\n");
else
{
for(i=;i<=ans;i++) printf("%c",s1[i]);
printf(" %d\n",ans+);
}
}
return ;
}
HDU 2594
(3)KMP匹配:
HDU 1711 Number Sequence http://acm.hdu.edu.cn/showproblem.php?pid=1711
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define N
int a[N],b[N];
int Next[N]; void getnext(int x[],int n)
{
int i,j;
Next[]=j=-;
for(i=;i<n;i++)
{
while(j>=&&x[j+]!=x[i])
j++;
if(x[j+]==x[i])
j++;
Next[i]=j;
}
} int kmp(int a[],int n,int b[],int m)
{
int i,j=-;
getnext(b,m);
for(i=;i<n;i++)
{
while(j>=&&b[j+]!=a[i])
j=Next[j];
if(a[i]==b[j+])
j++;
if(j+==m)
return i-m+;
}
return -;
} int main()
{
int T,n,m,i;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(i=;i<n;i++)
scanf("%d",&a[i]);
for(i=;i<m;i++)
scanf("%d",&b[i]);
int ans=kmp(a,n,b,m);
printf("%d\n",ans);
}
return ;
}
HDU 1711
CF 8A Train and Peter (string::find也可以) http://codeforces.com/problemset/problem/8/A
4.KMP模板
# include<cstdio>
# include<cstring>
# include<vector>
# include<algorithm>
using namespace std; # define VI vector<int> //返回所有匹配点
# define N
int Next[N]; void getnext(char *s)
{
int i,j,len=strlen(s);
Next[]=j=-;
for(i=;i<len;i++)
{
while(j>=&&s[j+]!=s[i]) j=Next[j];
if(s[j+]==s[i]) j++;
Next[i]=j;
}
} VI kmp(char *s,char *ch)
{
int i,j,len=strlen(s),m=strlen(ch);
VI ans;
ans.clear();
getnext(ch);
j=-;
for(i=;i<len;i++)
{
while(j>=&&ch[j+]!=s[i]) j=Next[j];
if(ch[j+]==s[i]) j++;
if(j+==m) ans.push_back(i-m+);
}
return ans;
}
KMP模板
5.总结:
KMP的应用很大,一定要深入理解,尤其是next数组, 这对处理字符串匹配问题有着重大影响,AC自动机就是基于KMP来实现的.同时也要理解next数组的局限性(只能是后缀与前缀的对应关系),这对解题时的判断有着重要作用
注:后缀数组可以解决KMP的一部分局限性
[数据结构]KMP小结的更多相关文章
- 数据结构--KMP算法总结
数据结构—KMP KMP算法用于解决两个字符串匹配的问题,但更多的时候用到的是next数组的含义,用到next数组的时候,大多是题目跟前后缀有关的 . 首先介绍KMP算法:(假定next数组已经学会, ...
- KMP Algorithm 字符串匹配算法KMP小结
这篇小结主要是参考这篇帖子从头到尾彻底理解KMP,不得不佩服原作者,写的真是太详尽了,让博主产生了一种读学术论文的错觉.后来发现原作者是写书的,不由得更加敬佩了.博主不才,尝试着简化一些原帖子的内容, ...
- 数据结构———KMP
今天照着课本敲了一下KMP.. 以OJ上的一个题为例敲了一下.. 题目:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem& ...
- 【暑假】[实用数据结构]KMP
KMP算法 KMP算法是字符串匹配算法,可以在O(n)的时间完成,算法包含两部分,分别是:构造适配函数与两串匹配. 失配边的使用大大提高了算法效率,可以理解为已经成功匹配的字符不在重新匹配,因为我们已 ...
- OpenJudge_cdqz 数据结构版块小结
题目整理 Challenge 0 随机线性存储表-easy Challenge 1 链表数组-easy Challenge 2 可持久化Treap的可持久化运用-hard Challenge 3 ...
- 实验数据结构——KMP算法Test.ming
翻译计划 小明初学者C++,它确定了四个算术.关系运算符.逻辑运算.颂值操作.输入输出.使用简单的选择和循环结构.但他的英语不是很好,记住太多的保留字,他利用汉语拼音的保留字,小屋C++,发明 ...
- 大话数据结构——KMP算法(还存在问题)
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html /*#include& ...
- KMP小结
1. KMP模版: 代表题目:POJ 3641 Oulipo KMP http://blog.csdn.net/murmured/article/details/12871891 char P[MAX ...
- 数据结构——KMP算法
算法介绍 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法).KMP算法的核心是利用 ...
随机推荐
- hdu5878 I Count Two Three(二分+ 打表)
题目链接:hdu5878 I Count Two Three 题意:给出一个整数n, 找出一个大于等于n的最小整数m, 使得m可以表示为2^a * 3^b * 5^c * 7^d. 题解:打表预处 ...
- SELECTION-SCREEN 加按钮
这是我喜欢的这种模式,选择屏加个新建按钮,直接跳转到主屏幕做单据. 选择屏就直接查询,双击查询结果跳转到主屏幕.... 做好编辑控制,事件处理...EVERYTHING IS SOOOOOOO NIC ...
- Linux Bash代码 利用for循环实现命令的多次执行
Linux Bash代码 [yuanhao15@lu01 libsvm-rank-2.81]$ for ((i=0; i<=19; i++)) do ./svm-train -s 5 -c 10 ...
- Facebook 内部高效工作PPT
Facebook 内部分享:不论你如何富有,你都赚不到更多的时间,你也回不到过去.没有那么多的假如,只有指针滴答的时光飞逝和你应该好好把握的现在,以下26张PPT的分享将为您带来时间价值管理的技巧. ...
- OpenTSDB介绍——基于Hbase的分布式的,可伸缩的时间序列数据库,而Hbase本质是列存储
原文链接:http://www.jianshu.com/p/0bafd0168647 OpenTSDB介绍 1.1.OpenTSDB是什么?主要用途是什么? 官方文档这样描述:OpenTSDB is ...
- BZOJ1962 模型王子
戳这里 /************************************************************** Problem: 1962 User: rausen Langu ...
- 3D开发的基本知识
为了实现3D图形,程序员需要定义两个方面的数据: 1.3D图形的每个顶点(Vertex)的位置,每个顶点的位置都需要X.Y.Z三个左标值. 2.3D图形每个面由哪些顶点组成. Android的3D坐标 ...
- android应用程序如何调用支付宝接口(转)
最近在做一个关于购物商城的项目,项目里面付款这块我选的是调用支付宝的接口,因为用的人比较多. 在网上搜索了以下,有很多这方面的教程,但大部分教程过于陈旧,而且描述的过于简单.而且支付宝提供的接口一直在 ...
- WPF 画刷应用
纯色: SolidColorBrush brush = new SolidColorBrush(Colors.White); window1.Background = brush; 渐变色: Line ...
- opencv+ffmpeg实现avi视频的播放
配了一天,终于成功的在ubuntu上安装了ffmpeg,实现了opencv对avi文件的读取. 在CvCapture* pCapture=cvCaptureFromAVI("video.av ...