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小结的更多相关文章

  1. 数据结构--KMP算法总结

    数据结构—KMP KMP算法用于解决两个字符串匹配的问题,但更多的时候用到的是next数组的含义,用到next数组的时候,大多是题目跟前后缀有关的 . 首先介绍KMP算法:(假定next数组已经学会, ...

  2. KMP Algorithm 字符串匹配算法KMP小结

    这篇小结主要是参考这篇帖子从头到尾彻底理解KMP,不得不佩服原作者,写的真是太详尽了,让博主产生了一种读学术论文的错觉.后来发现原作者是写书的,不由得更加敬佩了.博主不才,尝试着简化一些原帖子的内容, ...

  3. 数据结构———KMP

    今天照着课本敲了一下KMP.. 以OJ上的一个题为例敲了一下.. 题目:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem& ...

  4. 【暑假】[实用数据结构]KMP

    KMP算法 KMP算法是字符串匹配算法,可以在O(n)的时间完成,算法包含两部分,分别是:构造适配函数与两串匹配. 失配边的使用大大提高了算法效率,可以理解为已经成功匹配的字符不在重新匹配,因为我们已 ...

  5. OpenJudge_cdqz 数据结构版块小结

    题目整理 Challenge 0  随机线性存储表-easy Challenge 1  链表数组-easy Challenge 2  可持久化Treap的可持久化运用-hard Challenge 3 ...

  6. 实验数据结构——KMP算法Test.ming

    翻译计划     小明初学者C++,它确定了四个算术.关系运算符.逻辑运算.颂值操作.输入输出.使用简单的选择和循环结构.但他的英语不是很好,记住太多的保留字,他利用汉语拼音的保留字,小屋C++,发明 ...

  7. 大话数据结构——KMP算法(还存在问题)

    http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html /*#include& ...

  8. KMP小结

    1. KMP模版: 代表题目:POJ 3641 Oulipo KMP http://blog.csdn.net/murmured/article/details/12871891 char P[MAX ...

  9. 数据结构——KMP算法

    算法介绍 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法).KMP算法的核心是利用 ...

随机推荐

  1. 转载css层级优先级。

    解读CSS样式优先级(修改门户自定义样式必读) 一.什么是CSS优先级?所谓CSS优先级,即是指CSS样式在浏览器中被解析的先后顺序.当同一个元素(或内容)被多个CSS选择符选中时,就要按照优先权取舍 ...

  2. BootStrap 最佳资源合集(转)

    witter BootStrap是一款优秀的前端的框架,称得上是前端的一个框架利器.Web前端开发者每天都在与HTML.CSS.JavaScript打交道,然 而不少人都是在周而复始的写模板.样式和交 ...

  3. noip知识点总结之--欧几里得算法和扩展欧几里得算法

    一.欧几里得算法 名字非常高大上的不一定难,比如欧几里得算法...其实就是求两个正整数a, b的最大公约数(即gcd),亦称辗转相除法 需要先知道一个定理: gcd(a, b) = gcd(b, a  ...

  4. 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 ...

  5. 高效前端优化工具--Fiddler入门教程

    简介: Fiddler是用C#编写的一个免费的HTTP/HTTPS网络调试器.Fiddler是以代理服务器的方式,监听系统的网络数据流动英语中Fiddler是小提琴的意思,Fiddler Web De ...

  6. OL/SQL编程练习

    create or replace procedure pr_first is --一个变量 v_a ) := '总有一天我的生命将走到尽头'; --一个常量 c_b constant ) := '而 ...

  7. POJ 1979 Red and Black dfs 难度:0

    http://poj.org/problem?id=1979 #include <cstdio> #include <cstring> using namespace std; ...

  8. hdu 4631 Sad Love Story

    http://acm.hdu.edu.cn/showproblem.php?pid=4631 没想到这道题需要用“平均时间复杂度” 计算   一直没有想到解法  因为不符考虑了最坏情况的理念 方法一: ...

  9. 宜家的幸福生活,源于K2 BPM的支撑

    很久很久以前,有一篇很火的文章在各大网站被疯狂转载<一个在北欧生活10年的MM,告诉你为什么北欧全球幸福指数第一>,开头第一段就已经让人羡慕嫉妒恨了. "下午的四.五点钟,北欧人 ...

  10. Hadoop中常用的InputFormat、OutputFormat(转)

    Hadoop中的Map Reduce框架依赖InputFormat提供数据,依赖OutputFormat输出数据,每一个Map Reduce程序都离不开它们.Hadoop提供了一系列InputForm ...