KMP算法是处理字符串匹配的一种高效算法

它首先用O(m)的时间对模板进行预处理,然后用O(n)的时间完成匹配。从渐进的意义上说,这样时间复杂度已经是最好的了,需要O(m+n)时间。对KMP的学习可以为AC-自动机做铺垫,学习KMP算法的核心是要理解失配函数,比如一条状态链,其中编号为i的节点表示已经匹配了i个字符,匹配开始的状态是0,成功匹配状态是1(表示多匹配了一个字符),而失配时沿着“失配边”走。为方便起见,这里的失配函数f[i]表示状态i失配时应转移到的新状态,特别需要注意f[0]=0;

有了失配函数以后,KMP算法不难写出:

void find(char *t,char *p,int *f)
{
int n=strlen(t),m=strlen(p);
getfail(p,f);
int j=0;
for(int i=0;i<n;i++)
{
while(j&&p[j]!=t[i]) j=f[j];
if(p[j]==f[i]) j++;
if(j==m) printf("%d\n",i-m+1);
}
}

总的时间复杂度为O(n)

状态转移图是构造KMP的关键也是最巧妙的地方,算法思想就是自己匹配自己,进行递推:

void getfaile(char *p,int *f)
{
int m=strlen(p);
f[0]=0;
f[1]=0;
for(int i=1;i<m;i++)
{
int j=f[i];
while(j&&p[i]!=p[j]) j=f[j];
f[i+1]=p[i]==p[j] ? j+1 : 0;
}
}

求周期串类型(KMP模板题)

链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1027

题解:

根据后缀函数的定义,“错位部分”长度为i-f[i],如果这i个字符组成一个周期串,那么“错位”部分恰好是一个循环节,因此k(i-f[i])=i(注意k>1,因此i-f[i]不能等于i,必须有饭f[i]>0)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int maxn=1000000+10;
int f[maxn];
string p;
int main()
{
int n,cas=0;
while(cin>>n)
{
if(n==0) break;
cin>>p;
f[0]=0;
f[1]=0;
for(int i=1;i<n;i++)
{
int j=f[i];
while(j&&p[i]!=p[j]) j=f[j];
f[i+1]=p[i]==p[j] ? j+1 : 0;
}
printf("Test case #%d\n",++cas);
for(int i=2;i<=n;i++)
if(f[i]>0&&i%(i-f[i])==0)
printf("%d %d\n",i,i/(i-f[i]));
cout<<endl;
}
return 0;
}

KMP裸题(求子串重复的次数) (本人poj的第50题)

链接: http://poj.org/problem?id=3461

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000000+10;
int f[maxn];
char p[maxn],t[maxn];
int main()
{
int k;
cin>>k;
while(k--)
{
cin>>p>>t;
int n=strlen(t),m=strlen(p);
memset(f,0,sizeof(f));
f[0]=0;
f[1]=0;
for(int i=1;i<m;i++)
{
int j=f[i];
while(j&&p[i]!=p[j]) j=f[j];
f[i+1]=p[i]==p[j] ? j+1 : 0;
}
int j=0,tt=0;
for(int i=0;i<n;i++)
{
while(j&&p[j]!=t[i]) j=f[j];
if(p[j]==t[i]) j++;
if(j==m) ++tt;
}
cout<<tt<<endl;
}
return 0;
}

KMP找出第一次出现匹配的位置:

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1711

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000000+10;
int p[maxn],t[maxn];
int f[maxn];
int main()
{
int k;
scanf("%d",&k);
while(k--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d",&t[i]);
for(int i=0;i<m;i++)
scanf("%d",&p[i]);
memset(f,0,sizeof(f));
f[0]=0;
f[1]=0;
for(int i=1;i<m;i++)
{
int j=f[i];
while(j&&p[i]!=p[j]) j=f[j];
f[i+1]=p[i]==p[j] ? j+1 : 0;
}
int j=0,flag=0,tt;
for(int i=0;i<n;i++)
{
while(j&&p[j]!=t[i]) j=f[j];
if(p[j]==t[i]) j++;
if(j==m)
{
flag=1;
tt=i-m+2;
break;
}
}
if(flag==1)
printf("%d\n",tt);
else
printf("-1\n");
}
return 0;
}

求最短的重复串出现的次数

链接:http://poj.org/problem?id=2406

思路:KMP,next表示模式串如果第i位(设str[0]为第0位)与文本串第j位不匹配则要回到第next[i]位继续与文本串第j位匹配。则模式串第1位到next[n]与模式串第n-next[n]位到n位是匹配的。所以思路和上面一样,如果n%(n-next[n])==0,则存在重复连续子串,长度为n-next[n]。

例如:a    b    a    b    a    b

next:-1   0    0    1    2    3    4

next[n]==4,代表着,前缀abab与后缀abab相等的最长长度,这说明,ab这两个字母为一个循环节,长度=n-next[n];

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000000+10;
char p[maxn];
int f[maxn];
int main()
{
while(scanf("%s",p)!=EOF)
{
if(p[0]=='.') break;
int n=strlen(p);
memset(f,0,sizeof(f));
f[0]=0;
f[1]=0;
for(int i=1;i<n;i++)
{
int j=f[i];
while(j&&p[i]!=p[j]) j=f[j];
f[i+1]=p[i]==p[j] ? j+1 : 0;
}
if(n%(n-f[n])==0)
cout<<n/(n-f[n])<<endl;
else
cout<<"1"<<endl; }
return 0;
}

KMP算法在字符串中的应用的更多相关文章

  1. 51NOD 1292 1277(KMP算法,字符串中的有限状态自动机)

    在前两天的CCPC网络赛中...被一发KMP题卡了住了...遂决定,哪里跌倒就在哪里爬起来...把个KMP恶补一发,连带着把AC自动机什么的也整上. 首先,介绍设定:KMP算法计划解决的基本问题是,两 ...

  2. KMP算法 --- 在文本中寻找目标字符串

    KMP算法 --- 在文本中寻找目标字符串 很多时候,为了在大文本中寻找到自己需要的内容,往往需要搜索关键字.这其中就牵涉到字符串匹配的算法,通过接受文本和关键词参数来返回关键词在文本出现的位置.一般 ...

  3. 回朔法/KMP算法-查找字符串

    回朔法:在字符串查找的时候最容易想到的是暴力查找,也就是回朔法.其思路是将要寻找的串的每个字符取出,然后按顺序在源串中查找,如果找到则返回true,否则源串索引向后移动一位,再重复查找,直到找到返回t ...

  4. 基于KMP算法的字符串模式匹配问题

    基于KMP算法的字符匹配问题 反正整个清明都在纠结这玩意...差点我以为下个清明要给自己过了. 至于大体的理解,我就不再多说了(还要画图多麻烦鸭),我参考了以下两个博客,写的真的不错,我放了超链接,点 ...

  5. KMP算法 (字符串的匹配)

    视频参考 对于正常的字符串模式匹配,主串长度为m,子串为n,时间复杂度会到达O(m*n),而如果用KMP算法,复杂度将会减少线型时间O(m+n). 设主串为ptr="ababaaababaa ...

  6. 利用Manacher算法寻找字符串中的最长回文序列(palindrome)

    寻找字符串中的最长回文序列和所有回文序列(正向和反向一样的序列,如aba,abba等)算是挺早以前提出的算法问题了,最近再刷Leetcode算法题的时候遇到了一个(题目),所以就顺便写下. 如果用正反 ...

  7. [算法]去掉字符串中连续出现的k个0子串

    题目: 给定一个字符串str和一个整数k,如果str中正好有k个‘0’字符出现时,把k个连续的‘0’字符去除,返回处理后的字符串. 举例: str=”A00B”,k=2,返回“AB” str=”A00 ...

  8. KMP算法查找字符串

    假设长字符串为t,短字符串为p.为了进行KMP匹配,首先需要计算字符串p的next数组,后面实现了计算该数组的函数void KmpGenNext(char* p, int* next).对于”abca ...

  9. FZU 2122 又见LKity【字符串/正难则反/KMP/把一个字符串中某个部分替换为另一个部分】

    嗨!大家好,在TempleRun中大家都认识我了吧.我是又笨又穷的猫猫LKity.很高兴这次又与各位FZU的ACMer见面了.最近见到FZU的各位ACMer都在刻苦地集训,整天在日光浴中闲得发慌的我压 ...

随机推荐

  1. 【课余作品】简约QQ申请器(永久免费更新)

    UPDATEDATE:2013-08-28 下载地址:http://pan.baidu.com/share/link?shareid=3376000151&uk=3339155803

  2. 【BZOJ3939】Cow Hopscotch(动态开点线段树)

    题意: 就像人类喜欢跳格子游戏一样,FJ的奶牛们发明了一种新的跳格子游戏.虽然这种接近一吨的笨拙的动物玩跳格子游戏几乎总是不愉快地结束,但是这并没有阻止奶牛们在每天下午参加跳格子游戏  游戏在一个R* ...

  3. jQuery操作元素的class属性

    今天在做一个菜单折叠插件的时候需要根据页面的url改变其class属性.jQuery操作元素的属性是非常方便的,在此记录一下: 1.给元素添加class属性: addClass(class) (1)添 ...

  4. 2018 百度之星 初赛 第六题 HDU6349

    三原色图  Accepts: 281  Submissions: 1261  Time Limit: 1500/1000 MS (Java/Others)  Memory Limit: 262144/ ...

  5. Java添加、提取、替换和删除PDF图片

    (一)简介 这篇文章将介绍在Java中添加.提取.删除和替换PDF文档中的图片. 工具使用: Free Spire.PDF for JAVA 2.4.4(免费版) Intellij IDEA Jar包 ...

  6. freeswitch三方通话配置

    此种方法能实现,其中默认转移后按0,可进入三方通话. 用transfer只能实现代接转移. Misc. Dialplan Tools att xfer From FreeSWITCH Wiki Jum ...

  7. hdu 1068 Girls and Boys(匈牙利算法求最大独立集)

    Girls and Boys Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  8. samba.conf (香港中华厨房有限公司实例)

    # Sample configuration file for the Samba suite for Debian GNU/Linux. # # This is the main Samba con ...

  9. Intellij IDEA远程调试tomcat

    1.windows系统 文件catalina.bat首行增加下面代码 set CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE ...

  10. Python 离线等价类

    离线等价类的概念见离线等价类 最近在清洗数据的时候涉及到要将相似度比较高的文件夹合并,特征比对得到是1:1的对,比如: (a,b),(c,d),(a,c)...,那么合并的时候就涉及到将这些等价的对合 ...