[数据结构]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算法的核心是利用 ...
随机推荐
- 转载css层级优先级。
解读CSS样式优先级(修改门户自定义样式必读) 一.什么是CSS优先级?所谓CSS优先级,即是指CSS样式在浏览器中被解析的先后顺序.当同一个元素(或内容)被多个CSS选择符选中时,就要按照优先权取舍 ...
- BootStrap 最佳资源合集(转)
witter BootStrap是一款优秀的前端的框架,称得上是前端的一个框架利器.Web前端开发者每天都在与HTML.CSS.JavaScript打交道,然 而不少人都是在周而复始的写模板.样式和交 ...
- noip知识点总结之--欧几里得算法和扩展欧几里得算法
一.欧几里得算法 名字非常高大上的不一定难,比如欧几里得算法...其实就是求两个正整数a, b的最大公约数(即gcd),亦称辗转相除法 需要先知道一个定理: gcd(a, b) = gcd(b, a ...
- HADOOP :: java.lang.ClassNotFoundException: WordCount
I am using eclipse to export the jar file of a map-reduce program. When i am run the jar using comma ...
- 高效前端优化工具--Fiddler入门教程
简介: Fiddler是用C#编写的一个免费的HTTP/HTTPS网络调试器.Fiddler是以代理服务器的方式,监听系统的网络数据流动英语中Fiddler是小提琴的意思,Fiddler Web De ...
- OL/SQL编程练习
create or replace procedure pr_first is --一个变量 v_a ) := '总有一天我的生命将走到尽头'; --一个常量 c_b constant ) := '而 ...
- POJ 1979 Red and Black dfs 难度:0
http://poj.org/problem?id=1979 #include <cstdio> #include <cstring> using namespace std; ...
- hdu 4631 Sad Love Story
http://acm.hdu.edu.cn/showproblem.php?pid=4631 没想到这道题需要用“平均时间复杂度” 计算 一直没有想到解法 因为不符考虑了最坏情况的理念 方法一: ...
- 宜家的幸福生活,源于K2 BPM的支撑
很久很久以前,有一篇很火的文章在各大网站被疯狂转载<一个在北欧生活10年的MM,告诉你为什么北欧全球幸福指数第一>,开头第一段就已经让人羡慕嫉妒恨了. "下午的四.五点钟,北欧人 ...
- Hadoop中常用的InputFormat、OutputFormat(转)
Hadoop中的Map Reduce框架依赖InputFormat提供数据,依赖OutputFormat输出数据,每一个Map Reduce程序都离不开它们.Hadoop提供了一系列InputForm ...