KMP算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,其对于任何模式和目标序列,都可以在线性时间内完成匹配查找,而不会发生退化,是一个非常优秀的模式匹配算法。

举个例子来说,如果我想在字符串s(BBCABCEFABCDACEABCDACD)找是否存在子串t(ABCDABD)。

1.

我们先去找匹配第一个字符,发现字符串s第一个字符与字符串t的第一个字符不匹配,然后我们继续往后找。

2.

直到搜到s的第4个字符才找到和t的第一个字符匹配的字符。

3.

然后我们继续一位位搜。

4.

直到我们搜到不能匹配的位置。

5.

正常想法是直接移一位,然后再从头开始逐个比较。这样做虽然可行,但效率太低。而这个就是KMP与众不同的地方。

当E和B不匹配的时候,你已经匹配了前5个,也就是说你知道t串前面6个的信息,KMP正是利用了这个已知信息,不把搜索位置移回已经比较过的位置,继续把它向后移,这样就提高了效率。

6.

那么怎样往后移呢?,我们可以针对t建一张部分匹配表,那么这张表如何产生的呢?

"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例,

(以上两图均出自参考文献)

附上伪代码:

 nt[] = ;
int n = strlen(s);
for(int i = , j = ; i < n; i ++){
while(j != && s[j] != s[i]) j = nt[j - ];
nt[i] = s[j] == s[i] ? ++ j : ;
}

7.

然后,我们继续来看,我们发现最后一个匹配的字母为A,部分匹配值为1,根据移动公式:

移动位数 = 已匹配的字符数 - 对应的部分匹配值

5 - 1 = 4,所以向后移4位,变成上图。然后我们发现B和E仍旧不能匹配,此时算出需要移动位数为1,然后便有了下图。

之后我们发现A和E不能匹配,然后我们继续一位一位移,知道再找到一个A。

8.

然后我们又搜到了A,然后我们可以继续匹配啦。

9.

知道搜到最后一位(啊呀就差一点就能完全匹配,可惜),然后我们发现要移动4位。

10.

然后我们继续匹配,发现到最后刚好匹配完(好开心,找到了!)如下图:

附上总代码:

 #include <cstdio>
#include <cstring>
const int N = + ;
char s[N];
int nt[N];
char t[N]; void work(){
nt[] = ;
int n = strlen(s);
for(int i = , j = ; i < n; i ++){
while(j != && s[j] != s[i]) j = nt[j - ];
nt[i] = s[j] == s[i] ? ++ j : ;
//printf("nt[%d] = %d\n", i, nt[i]);
}
int p = ;
int q = ;
int lt = strlen(t);
int ans = ;
while(p + q < lt){
if(s[p] == t[p + q]){
while(s[p] == t[p + q] && p < n) p += ;
//printf("p = %d\n", p);
if(p == n)ans += ;
int w = p - nt[p - ];
p = nt[p - ];
q += w;
}
else {
while(p != && s[p] != t[p + q]) p = nt[p - ];
q += ;
}
}
printf("%d\n", ans);
} int main() {
//while(scanf("%s%s", s, t) == 2) work();
int T;
scanf("%d", &T);
while(T--){
scanf("%s%s", s, t);
work();
}
return ;
}

参考文献:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html

字符串匹配(KMP算法)的更多相关文章

  1. 字符串匹配KMP算法详解

    1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有比较详细的通俗易懂的讲解,另一方面也怪自己没有沉下心来研究.最近在leetcode上又遇见字符串匹配的题目,以此 ...

  2. 字符串匹配KMP算法

    1. 字符串匹配的KMP算法 2. KMP算法详解 3. 从头到尾彻底理解KMP

  3. 字符串匹配--kmp算法原理整理

    kmp算法原理:求出P0···Pi的最大相同前后缀长度k: 字符串匹配是计算机的基本任务之一.举例,字符串"BBC ABCDAB ABCDABCDABDE",里面是否包含另一个字符 ...

  4. 字符串匹配KMP算法的C语言实现

    字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...

  5. 字符串匹配KMP算法的讲解C++

    转自http://blog.csdn.net/starstar1992/article/details/54913261 也可以参考http://blog.csdn.net/liu940204/art ...

  6. 字符串匹配KMP算法(转自阮一峰)

    转自 http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 字符串匹配是计算 ...

  7. 【Luogu P3375】字符串匹配KMP算法模板

    Luogu P3375 模式串:即题目中的S2所代表的意义 文本串:即题目中的S1所代表的意义 对于字符串匹配,有一种很显然的朴素算法:在S1中枚举起点一位一位匹配,失配之后起点往后移动一位,从头开始 ...

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

    关于KMP算法的分析,我觉得这两篇博客写的不错: http://www.ruanyifeng.com/blog/2013/05/Knuth–Morris–Pratt_algorithm.html ht ...

  9. 字符串匹配—KMP算法

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

  10. <字符串匹配>KMP算法为何比暴力求解的时间复杂度更低?

    str表示文本串,m表示模式串; str[i+j] 和 m[j] 是正在进行匹配的字符; KMP的时间复杂度是O(m+n)  ,  暴力求解的时间复杂度是O(m*n) KMP利用了B[0:j]和A[i ...

随机推荐

  1. Erlang 虚拟机 BEAM 指令集之内存管理相关的指令

    翻看 BEAM 虚拟机指令集的时候(在编译器源码目录下:lib/compiler/src/genop.tab),会发现有一些和内存分配/解除分配相关的指令,如下所示: allocate StackNe ...

  2. esxi安装全过程及基本配置

    esxi6.0下载地址 链接: http://pan.baidu.com/s/1jIfg2yU 密码: qacv 支持检测可以参考:http://www.linuxidc.com/Linux/2012 ...

  3. Lighttpd

    一.简介 Lighttpd 是一个德国人领导的开源Web服务器软件,其根本的目的是提供一个专门针对高性能网站,安全.快速.兼容性好并且灵活的web server环境.具有非常低的内存开销,cpu占用率 ...

  4. Swift 语法笔记01

    Swift 好多新奇的地方啊...妈的 var display: int { get() set() } Tuple: let x: (d:Double, e:String, f:Int) = (3. ...

  5. 好玩的-记最近玩的几个经典ipad ios游戏

    最近回了趟家,在家里闲着没事去app store找了找一些高分游戏玩一玩,下面就是我最近玩的游戏. 海岛奇兵 想必大家都很了解,这是由开发过clash of clan部落冲突的公司所开发的另一款多人策 ...

  6. Apache Commons 常用工具类整理

    其实一直都在使用常用工具类,只是从没去整理过,今天空了把一些常用的整理一下吧 怎么使用的一看就明白,另外还有注释,最后的使用pom引入的jar包 public class ApacheCommonsT ...

  7. Android网络之数据解析----使用Google Gson解析Json数据

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  8. Linux搭建python环境中cx_Oracle模块安装遇到的问题与解决方法

    安装或使用cx_Oracle时,需要用到Oracel的链接库,如libclntsh.so.11.1,否则会有各种各样的错误信息. 安装Oracle Instant Client就可得到这个链接库,避免 ...

  9. Android Studio 三种添加插件的方式,androidstudio

    前几篇blog我们介绍了如何安装和配置Android Studio,这篇Blog我们来聊聊如何给Android Studio添加插件,添加插件的路径有三种,我把他们分类如下: 点击设置小按钮 点击[P ...

  10. Python-面向对象编程

    概述: 面向过程:根据业务逻辑从上到下写代码. 函数式:将某功能代码封装到函数中,以后便无需重复编写,进调用函数即可. 面向对象:对函数进行分类和封装,让开发“更快更好更强” 创建类和对象 面向对象编 ...