KMP(字符串匹配)算法 O(m+n)
在长度为m字符串中匹配长度为n的字符串
加快回溯:(1)建立回溯数组,O(n) ;(2)开始匹配,失败则回溯匹配串下标,O(m)
Next [ ]数组 : Next [ k ]表示k及K之前最长的等长前后缀 (P[0...j-1]中最长后缀的长度等于相同字符序列的前缀),k为下标
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|||~~~~~~~~~~~| || ~~~~~~~~~~~|||
------------------------------------------------------------------------------------------------------------------------------
|||~~~~~~~~~~~|| |||
KMP算法
在介绍KMP算法之前,先介绍一下BF算法。
一.BF算法
BF算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串P的第一个字符进行匹配,若相等,则继续比较S的第二个字符和P的第二个字符;若不相等,则比较S的第二个字符和P的第一个字符,依次比较下去,直到得出最后的匹配结果。
举例说明:
S: ababcababa
P: ababa
BF算法匹配的步骤如下
i=0 i=1 i=2 i=3 i=4
第一趟:ababcababa 第二趟:ababcababa 第三趟:ababcababa 第四趟:ababcababa 第五趟:ababcababa
ababa ababa ababa ababa ababa
j=0 j=1 j=2 j=3 j=4(i和j回溯)
i=1 i=2 i=3 i=4 i=3
第六趟:ababcababa 第七趟:ababcababa 第八趟:ababcababa 第九趟:ababcababa 第十趟:ababcababa
ababa ababa ababa ababa ababa
j=0 j=0 j=1 j=2(i和j回溯) j=0
i=4 i=5 i=6 i=7 i=8
第十一趟:ababcababa 第十二趟:ababcababa 第十三趟:ababcababa 第十四趟:ababcababa 第十五趟:ababcababa
ababa ababa ababa ababa ababa
j=0 j=0 j=1 j=2 j=3
i=9
第十六趟:ababcababa
ababa
j=4(匹配成功)
代码实现:
int BFMatch( char *s, char *p)
|
{
|
int i,j;
|
i=0;
|
while (i< strlen (s))
|
{
|
j=0;
|
while (s[i]==p[j]&&j< strlen (p))
|
{
|
i++;
|
j++;
|
}
|
if (j== strlen (p))
|
return i- strlen (p);
|
i=i-j+1; //指针i回溯
|
}
|
return -1;
|
}
|
其实在上面的匹配过程中,有很多比较是多余的。在第五趟匹配失败的时候,在第六趟,i可以保持不变,j值为2。因为在前面匹配的过程中,对于串S,已知s0s1s2s3=p0p1p2p3,又因为p0!=p1!,所以第六趟的匹配是多余的。又由于p0==p2,p1==p3,所以第七趟和第八趟的匹配也是多余的。在KMP算法中就省略了这些多余的匹配。
二.KMP算法
KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字。其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题,只需确定下次匹配j的位置即可,使得问题的复杂度由O(mn)下降到O(m+n)。
在KMP算法中,为了确定在匹配不成功时,下次匹配时j的位置,引入了next[]数组,next[j]的值表示P[0...j-1]中最长后缀的长度等于相同字符序列的前缀。
对于next[]数组的定义如下:
1)next[j]=-1 j=0
2)next[j]=max k:0<k<j P[0...k-1]=P[j-k,j-1]
3)next[j]=0 其他
如:
P a b a b a
j 0 1 2 3 4
next -1 -1 0 1 2
即next[j]=k>0时,表示P[0...k-1]=P[j-k,j-1]
因此KMP算法的思想就是:在匹配过程称,若发生不匹配的情况,如果next[j]>=0,则目标串的指针i不变,将模式串的指针j移动到next[j]的位置继续进行匹配;若next[j]=-1,则将i右移1位,并将j置0,继续进行比较。
代码实现如下:
int KMPMatch( char *s, char *p)
|
{
|
int next[100];
|
int i,j;
|
i=0;
|
j=0;
|
getNext(p,next);
|
while (i< strlen (s))
|
{
|
if (j==-1||s[i]==p[j])
|
{
|
i++;
|
j++;
|
}
|
else
|
{
|
j=next[j]; //消除了指针i的回溯
|
}
|
if (j== strlen (p))
|
return i- strlen (p);
|
}
|
return -1;
|
}
|
1.按照递推的思想:
根据定义next[0]=-1,假设next[j]=k, 即P[0...k-1]==P[j-k,j-1]
1)若P[j]==P[k],则有P[0..k]==P[j-k+1,j],很显然,next[j+1]=next[j]+1=k+1;
2)若P[j]!=P[k],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,显然k=next[k]。
因此可以这样去实现:
void getNext( char *p, int *next)
|
{
|
int j,k;
|
next[0]=-1;
|
j=0;
|
k=-1;
|
while (j< strlen (p)-1)
|
{
|
if (k==-1||p[j]==p[k]) //匹配的情况下,p[j]==p[k]
|
{
|
j++;
|
k++;
|
next[j]=k;
|
}
|
else //p[j]!=p[k]
|
k=next[k];
|
}
|
}
|
2.直接求解方法
void getNext( char *p, int *next)
|
{
|
int i,j,temp;
|
for (i=0;i< strlen (p);i++)
|
{
|
if (i==0)
|
{
|
next[i]=-1; //next[0]=-1
|
}
|
else if (i==1)
|
{
|
next[i]=0; //next[1]=0
|
}
|
else
|
{
|
temp=i-1;
|
for (j=temp;j>0;j--)
|
{
|
if (equals(p,i,j))
|
{
|
next[i]=j; //找到最大的k值
|
break ;
|
}
|
}
|
if (j==0)
|
next[i]=0;
|
}
|
}
|
}
|
bool equals( char *p, int i, int j) //判断p[0...j-1]与p[i-j...i-1]是否相等
|
{
|
int k=0;
|
int s=i-j;
|
for (;k<=j-1&&s<=i-1;k++,s++)
|
{
|
if (p[k]!=p[s])
|
return false ;
|
}
|
return true ;
|
KMP(字符串匹配)算法 O(m+n)相关推荐
- KMP算法小总结 洛谷P3375 【模板】KMP字符串匹配
提问:这里有一个长度为n的字符串str1和长度为m的字符串str2(n > = m),问在str1中str2出现了几次? 如果使用暴力求解,一个一个比较,在n和m都极大的情况下将花费非常多的不必 ...
- 落谷 P3375 【模板】KMP字符串匹配
题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next. 输入格式: 第一行为一个字符串,即为s1 ...
- Oulipo-欧力波(KMP字符串匹配问题)
Oulipo-欧力波 HDU - 1686 The French author Georges Perec (1936–1982) once wrote a book, La disparition, ...
- Simpsons’ Hidden Talents辛普森一家的隐藏天赋(next数组和kmp字符串匹配)
辛普森一家的隐藏天赋 HDU - 2594 目录 辛普森一家的隐藏天赋 HDU - 2594 题意描述:当给定字符串s1和s2时,找到s1中最长的前缀,即s2的后缀.如果有,输出相同的字符串即字符串长 ...
- KMP算法详解P3375 【模板】KMP字符串匹配题解
KMP算法详解: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt(雾)提出的. 对于字符串匹配问题(such as 问你在abababb中有多少个 ...
- 数据结构 kmp字符串匹配_用动画解释 KMP 算法
大家好,我是一个每天在互联网都被读者催更催到爆肝,爆肾小鹿童鞋. 说实话,一些数据结构和算法我这辈子都不可能用到实际当中,但个人一直觉得能把复杂的东西讲明白是一件很牛逼的事情. 毕竟想牛逼也是很难的, ...
- 【模板】KMP字符串匹配
题目描述 给出两个字符串 s_1s1 和 s_2s2,若 s_1s1 的区间 [l, r][l,r] 子串与 s_2s2 完全相同,则称 s_2s2 在 s_1s1 中出现了,其出现位置为 ...
- KMP(字符串匹配)+字符串哈希
KMP非常不好理解,建议在网上搜KMP的视频看看,反正非常难理解,我想了好久好久(KMP的关键就在于求Next数组D,求前缀后缀) 下面的D题,B题稍稍有变化 ,C题只用求前缀后缀就只用求next数组 ...
- 【luogu 3375】【模板】KMP字符串匹配
题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next. (如果你不知道这是什么意思也不要问,去百度 ...
最新文章
- 《强化学习周刊》第12期:强化学习应用之组合优化
- 高斯--塞德尔迭代法求方程组的解(Python实现)
- oracle常用的时间格式转换
- 学业水平考试网登录_江西2020年下半年普通高中学业水平考试成绩查询时间及入口...
- 探秘 | 平安人寿人工智能研发团队北京研发中心
- 几种Lucene.Net打开IndexReader的方式
- jQuery---过滤选择器
- .net core razor ajax,.NET CORE Razor Pages Ajax 调用 C# 方法
- Linux tshark发送抓取的数据到kafka
- Apache(httpd) 报错You don't have permission to access /on this server.
- vijos1942——小岛 Floyed
- Boost升压电路调试
- 基于微信教室图书馆座位预约小程序毕业设计毕设作品(6)开题答辩PPT
- CSR8675项目实战:BlueAg蓝牙一拖二发射器
- 云终端服务器属于计算机设备吗,云终端不等于云电脑
- 计算机更改刷新频率,电脑屏幕刷新频率无法更改怎么办
- bem css_CSS体系结构:块元素修饰符(BEM)和原子CSS
- Coverage Path Planning(区域覆盖)
- Python 类变量,成员变量,静态变量,局部变量
- 所有职位 岗位 大全 看看都有些什么岗位 职位