[C++] [算法] KMP算法
KMP串匹配算法是一个经典的算法。
传统BF算法是传统的字符串匹配算法。很好理解。叶实现。但时间复杂度太高。
本文将从字符串模式字符串被称为。为了匹配字符串被称为主弦。
KMP配时能够少移动从串的位置,从而保持主串的索引不移动。
1 原理
如上图所看到的,假设在从串中有A=B,然后在匹配的时候,发现B后面的字符与X后面的字符不匹配,又因为B=X,因此,就有X=A,那么。在下次比較的时候就不用回溯了,直接比較X后面的字符与A后面的字符。
这样就行使遍历主串的索引不移动,仅仅移动从串的索引。因此。时间复杂度就是O(P.size())。
2 实现
问题是,怎样在匹配之前获知A=B这一信息呢?也就是,当X后面的字符与B后面的字符不相等时,遍历从串的索引怎样移动呢?
为此,引入了next数组,它可以保存A=B这一信息。
比方ababd,它的next数组就是:-1,-1,0,1,-1。
有人或许要问。这个结果与《算法导论》上的结果不一样啊,这是由于《算法导论》上的字符串的索引是以1開始,因此。next数组的值是以0開始,在这里。数组的索引以0開始。因此,next数组的值是以-1開始。
我们先来学会怎样使用next数组。之后再来看怎样得到next数组。
已知next数组,就能够得到kmp算法的匹配函数:
int kmp(const string& str1, const string& str2)
{
if(str1.size() < str2.size()) {
return -1;
} int j = -1;
for(int i = 0; i < str1.size(); ++i) {
while(str1[i] != str2[j + 1] && j >= 0) {
j = next[j];
}
if(str1[i] == str2[j + 1]) {
++j;
}
if(j == str2.size() - 1) {
return i - j;
}
}
return -1;
}
当中str1是主串。str2是从串。i用于遍历主串。j用于遍历从串。将j后面的一个字符与i位置的字符进行比較,假设不相等,而且j >= 0,就将j = next[j]。这里为什么要推断j >= 0呢?当j == -1时,说明str1[i] != str2[0]。那么。就不能运行j = next[j],而应该直接++i。因此,j == -1是str1[i] != str2[j+1]的特殊情况,它要单独提出来。因此,假设跳出了while循环。就有两种情况,一种是str[i] == str2[j+1],还有一种是j
== -1,假设str1[i] == str2[j+1]。就比較下一个。运行++j。
比方,上面的ababd,next数组为-1,-1,0,1,-1。主串为abaababd。
比較过程为:
abaababd
ababd
(1) 開始i = 0, j = -1。str1[0] == str2[0],++i, ++j => i = 1, j = 0。
(2) i = 1, j = 0。str1[1] == str2[1],++i, ++j => i = 2, j = 1。
(3) i = 2, j = 1。str1[2] == str2[2]。++i, ++j => i = 3, j = 2。
(4) i = 3, j = 2。str1[3] != str2[3] && j >= 0。j = next[j] = next[2] = 0 => i = 3, j = 0。
(5) i = 3, j = 0。
str1[3] != str2[1] && j >= 0。j = next[j] = next[0] = -1 => i = 3, j = -1。
(6) i = 3, j = -1。
str1[3] == str2[0]。++i, ++j => i = 4, j = 0。
(7) i = 4, j = 0。str1[4] == str2[1],++i, ++j => i = 5, j = 1。
(7) i =5, j = 1。str1[5] == str2[2],++i, ++j => i = 6, j = 2。
(7) i = 6, j = 2。str1[6] == str2[3],++i, ++j => i = 7, j = 3。
(7) i = 7, j = 3。str1[7] == str2[4]。++i, ++j => i = 8, j = 4。
此时j == ababd.size() - 1,也就是从串比較完毕了。因此,找到了一个匹配串。此时i指向主串中最后匹配的那个字符。而j指向从串中最后匹配的那个字符。
从而,i - j就得到匹配的串在主串中的起始索引。
3 分析
因此。KMP的实现方式是:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVvZmVuZ21hY2hlbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="500" height="300" alt="">
从图中能够看到,在从串中,0~j与主串中的i-j-1~i-1一样,然而。当比較主串中的i与从串中的j+1时,发现不匹配,此时,因为从串中的0~next[j]与j-next[j]~j一样,于是有:
从串中的0~next[j]与主串中的i-next[j]-1~i-1一样。因此。能够直接将j = next[j],直接将j跳到下次匹配的位置。而i不变。
因此,next[j]的意义是:因为从串中0~j子串中。前面一部分和后面一部分一样。于是,当0~j与主串匹配而j+1位置不匹配时,下次匹配j的位置。
所以。開始循环之前。没有匹配串,j的值就是-1,而《算法导论》中,字符串以1開始,那么,没有匹配串时,j的值就是0。
4 next数组的产生
知道了怎样使用next数组,然后就是怎样获得next数组了。
void get_next(const string& str, vector<int> &next)
{
next[0] = -1;
int j = -1; for(int i = 1; i < str.size(); ++i) {
while(str[i] != str[j + 1] && j >= 0) {
j = next[j];
}
if(str[i] == str[j + 1]) {
++j;
}
next[i] = j;
}
}
能够看出,next数组的生成跟kmp算法的实现方式类似。
事实上,从next数组的意义就能够看出。next数组的生成方式也是一个字符串的匹配过程。
假设str[i] == str[j+1],那么str中0~j+1与i-j-1~i一样,再将++j,变0~j与i-j~i等同。然后,next[i] = j。
版权声明:本文博主原创文章,博客,未经同意不得转载。
[C++] [算法] KMP算法的更多相关文章
- 数据结构与算法--KMP算法查找子字符串
数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章.这篇文章.还有这篇他们写得非常棒.结合他们的解释和自己的理解,完成了本文. 上一节介绍了暴力法查找子字符串,同时也发 ...
- 经典算法 KMP算法详解
内容: 1.问题引入 2.暴力求解方法 3.优化方法 4.KMP算法 1.问题引入 原始问题: 对于一个字符串 str (长度为N)和另一个字符串 match (长度为M),如果 match 是 st ...
- 笔记-算法-KMP算法
笔记-算法-KMP算法 1. KMP算法 KMP算法是一种改进的字符串匹配算法,KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是实现一 ...
- 值得花费一周研究的算法 -- KMP算法(indexOf)
KMP算法是由三个科学家(kmp分别是他们名字的首字母)创造出来的一种字符串匹配算法. 所解决的问题: 求文本字符串text内寻找第一次出现字符串s的下标,若未出现返回-1. 例如 text : &q ...
- 程序员必会算法-KMP算法
KMP算法是一种优秀的字符串匹配算法,字符串匹配的常规算法是一步一步进行移位和比较操作,直至找到完全相匹配的字符串. 下面通过一个例子,为大家仔细说明KMP算法的使用和思路: 问题: 在字符串“DEA ...
- 算法 kmp算法
kmp算法是改进后的字符匹配算法,它与bf算法的区别是,每次从串与主串匹配失败后,从串与主串匹配的位置不同. 下面具体说下这两种算法的区别: 主串:BABCDABABCDABCED 从串:ABCDAB ...
- BF算法 + KMP算法
准备: 字符串比大小:比的就是字符串里每个字符的ASCII码的大小.(其实这样的比较没有多大的意义,我们关心的是字符串是否相等,即匹配等) 字符串的存储结构:同线性表(顺序存储+链式存储) 顺序存储结 ...
- 图解算法——KMP算法
KMP算法 解决的是包,含问题. Str1中是否包含str2,如果包含,则返回子串开始位置.否则返回-1. 示例1: Str1:abcd123def Str2:123d 暴力法: 从str1的第一个字 ...
- 字符串匹配算法——KMP算法
处理字符串的过程中,难免会遇到字符匹配的问题.常用的字符匹配方法 1. 朴素模式匹配算法(Brute-Force算法) 求子串位置的定位函数Index( S, T, pos). 模式匹配:子串的定位操 ...
随机推荐
- [转]我的第一个WCF
1:首先新建一个解决方案 2:右击解决方案添加一个控制台程序 3:对着新建好的控制台程序右击添加wcf服务 最后的结果: 有3个文件 app.config Iwcf_server.cs wcf_se ...
- AJAX编程模板
AJAX一直以来没怎么接触,主要是做JSON数据在服务器和客户端之间传递的时候,被玩坏了,对它莫名的不可爱,最近心理阴影小了,于是又来看看它....... AJAX即“Asynchronous Jav ...
- 安装search everything中文语言包
Everything 作为很多人的必备工具,特写这篇文章,一方面让想使用国外优秀软件的英语小白有一段过渡期,另一方面也为自己整理下资料.当然,这个可不是不学好英语的正当理由. 步骤: 1. 下载好se ...
- 转:基于HTTP协议的轻量级开源简单队列服务:HTTPSQS
[文章作者:张宴 本文版本:v1.7.1 最后修改:2011.11.04 转载请注明原文链接:http://blog.zyan.cc/httpsqs/] HTTPSQS(HTTP Simple Que ...
- win32控制台实现按任意键退出的功能
win7之后的五win32 控制台出现了程序运行完之后就立即结束的问题,程序员根本无法看输出的结果.未来让控制台运行完之后能够等待程序员的操作.可以使用: system("PAUSE&quo ...
- BZOJ 1033 杀蚂蚁
Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的任 ...
- [BZOJ 1048] [HAOI2007] 分割矩阵 【记忆化搜索】
题目链接:BZOJ - 1048 题目分析 感觉这种分割矩阵之类的题目很多都是这样子的. 方差中用到的平均数是可以直接算出来的,然后记忆化搜索 Solve(x, xx, y, yy, k) 表示横坐标 ...
- Promise 让异步更优
每个异步方法都返回一个Promise 更优雅. then方法 每一个Promise 都有一个叫then 的方法, 接受一对callback 被解决时调用,resolve, 被拒绝 reje ...
- Unity3d 项目管理 版本管理
Unity3d中项目管理 版本管理 如果在提交文件的时候发现提示有"先更新,再提交的"提示的时候,这是因为,A提交了一个版本文件,版本是13,那么你还在修改版本为12的文件 ...
- Tunnel Warfare
hdu1540:http://acm.hdu.edu.cn/showproblem.php?pid=1540 题意:给你一列村庄,每个村庄给一个标号,1--n,然后毁掉一些村庄,或者重建几个村庄,重建 ...