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算法的更多相关文章

  1. 数据结构与算法--KMP算法查找子字符串

    数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章.这篇文章.还有这篇他们写得非常棒.结合他们的解释和自己的理解,完成了本文. 上一节介绍了暴力法查找子字符串,同时也发 ...

  2. 经典算法 KMP算法详解

    内容: 1.问题引入 2.暴力求解方法 3.优化方法 4.KMP算法 1.问题引入 原始问题: 对于一个字符串 str (长度为N)和另一个字符串 match (长度为M),如果 match 是 st ...

  3. 笔记-算法-KMP算法

    笔记-算法-KMP算法 1.      KMP算法 KMP算法是一种改进的字符串匹配算法,KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是实现一 ...

  4. 值得花费一周研究的算法 -- KMP算法(indexOf)

    KMP算法是由三个科学家(kmp分别是他们名字的首字母)创造出来的一种字符串匹配算法. 所解决的问题: 求文本字符串text内寻找第一次出现字符串s的下标,若未出现返回-1. 例如 text : &q ...

  5. 程序员必会算法-KMP算法

    KMP算法是一种优秀的字符串匹配算法,字符串匹配的常规算法是一步一步进行移位和比较操作,直至找到完全相匹配的字符串. 下面通过一个例子,为大家仔细说明KMP算法的使用和思路: 问题: 在字符串“DEA ...

  6. 算法 kmp算法

    kmp算法是改进后的字符匹配算法,它与bf算法的区别是,每次从串与主串匹配失败后,从串与主串匹配的位置不同. 下面具体说下这两种算法的区别: 主串:BABCDABABCDABCED 从串:ABCDAB ...

  7. BF算法 + KMP算法

    准备: 字符串比大小:比的就是字符串里每个字符的ASCII码的大小.(其实这样的比较没有多大的意义,我们关心的是字符串是否相等,即匹配等) 字符串的存储结构:同线性表(顺序存储+链式存储) 顺序存储结 ...

  8. 图解算法——KMP算法

    KMP算法 解决的是包,含问题. Str1中是否包含str2,如果包含,则返回子串开始位置.否则返回-1. 示例1: Str1:abcd123def Str2:123d 暴力法: 从str1的第一个字 ...

  9. 字符串匹配算法——KMP算法

    处理字符串的过程中,难免会遇到字符匹配的问题.常用的字符匹配方法 1. 朴素模式匹配算法(Brute-Force算法) 求子串位置的定位函数Index( S, T, pos). 模式匹配:子串的定位操 ...

随机推荐

  1. [转]我的第一个WCF

    1:首先新建一个解决方案 2:右击解决方案添加一个控制台程序 3:对着新建好的控制台程序右击添加wcf服务 最后的结果: 有3个文件 app.config  Iwcf_server.cs wcf_se ...

  2. AJAX编程模板

    AJAX一直以来没怎么接触,主要是做JSON数据在服务器和客户端之间传递的时候,被玩坏了,对它莫名的不可爱,最近心理阴影小了,于是又来看看它....... AJAX即“Asynchronous Jav ...

  3. 安装search everything中文语言包

    Everything 作为很多人的必备工具,特写这篇文章,一方面让想使用国外优秀软件的英语小白有一段过渡期,另一方面也为自己整理下资料.当然,这个可不是不学好英语的正当理由. 步骤: 1. 下载好se ...

  4. 转:基于HTTP协议的轻量级开源简单队列服务:HTTPSQS

    [文章作者:张宴 本文版本:v1.7.1 最后修改:2011.11.04 转载请注明原文链接:http://blog.zyan.cc/httpsqs/] HTTPSQS(HTTP Simple Que ...

  5. win32控制台实现按任意键退出的功能

    win7之后的五win32 控制台出现了程序运行完之后就立即结束的问题,程序员根本无法看输出的结果.未来让控制台运行完之后能够等待程序员的操作.可以使用: system("PAUSE&quo ...

  6. BZOJ 1033 杀蚂蚁

    Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的任 ...

  7. [BZOJ 1048] [HAOI2007] 分割矩阵 【记忆化搜索】

    题目链接:BZOJ - 1048 题目分析 感觉这种分割矩阵之类的题目很多都是这样子的. 方差中用到的平均数是可以直接算出来的,然后记忆化搜索 Solve(x, xx, y, yy, k) 表示横坐标 ...

  8. Promise 让异步更优

    每个异步方法都返回一个Promise 更优雅. then方法 每一个Promise  都有一个叫then 的方法, 接受一对callback    被解决时调用,resolve, 被拒绝   reje ...

  9. Unity3d 项目管理 版本管理

    Unity3d中项目管理     版本管理 如果在提交文件的时候发现提示有"先更新,再提交的"提示的时候,这是因为,A提交了一个版本文件,版本是13,那么你还在修改版本为12的文件 ...

  10. Tunnel Warfare

    hdu1540:http://acm.hdu.edu.cn/showproblem.php?pid=1540 题意:给你一列村庄,每个村庄给一个标号,1--n,然后毁掉一些村庄,或者重建几个村庄,重建 ...