Knuth-Morris-Pratt Algorithm

KMP背景分析



普通算法(遍历),会遗忘所有之前比较过的信息,导致每一次移位,都要重新重头比较每一个字符。这将会导致 O(mn)的时间复杂度(m: 关键字符长度,n: 文本string的长度)

而KMP算法,则能够保证不去重复比较已经部分匹配的字符,比如序列“abcdabac”,如果“abcd”部分匹配了文本,而在接下来的“d”位置上不匹配,那么算法则会直接跳过4个位置,重新进行比较,而不是移位1个,从头进行比较。这样就能够保证时间复杂度为 O(n)。说通俗一些就是直接跳到公共前后缀的位置:

图中阴影部分代表公共前后缀,对于“abcdabac”就是“ab”

为了保证上述复杂度,需要对关键字符进行预处理(就是标明最长公共前后缀的辅助数组),而这一过程的时间复杂度为 O(m)。因为 m<n,所以总的算法时间复杂度为 O(n)

一些定义


令 x = abacab,那么x的一些术语描述如下:

proper prefixes 前缀:

a, ab, aba, abac, abaca

proper suffixes 后缀:

b, ab, cab, acab, bacab

borders 边界(前,后缀共有的最长子串):

ab

边界 ab 拥有 2 的宽度

而我们的预处理,就是对 关键字字符串 算出每个位置上的 边界。

比如:

j: 0 1 2 3 4 5

p[j]: a b a b a a

b[j]: 0 0 1 2 3 1

预处理过程


该过程就是生成 partial match table 或者称为 failure function的算法,即生成 b[j] 数组。

b[j]的生成过程,其实可以对关键字符串P,用 递推方式 算出来,时间复杂度为 O(m)

假设 b[0], ..., b[i-1] 已知,那么 边界b[i] 的值,通过比较 Pj,Pi 可以得到

如果Pj==Pi,那么 b[i] = b[j-1] + 1

如果不相等,那么需要重新获得下一个最大边界长度,这里需要用到如下定理:

当字符串x的最大边界是s,次大边界是r,可以推得s的最大边界就是r。

当想扩展x的 边界s 不成功,那么就把x的边界变为s的边界r,重新扩展:

使用如下例子,关键子字符串P:

j‘      j             i i‘

a a a b a a e e a a a b a a a ...

|r|                     |r|

|----s----|     |----s----|

|------------P------------|...

当前的位置i的最大边界是s,次大边界是r。假设当点边界s的宽度是 j = 6。

当i移动到下一个位置i‘的时候,“e”和“a”并不相等,边界无法拓展,于是更新 j = b[j-1], 于是j更新为r的宽度2,记为j‘

再次比较Pj‘ 和 Pi‘是否相等,发现相等,于是更新b[i‘] = b[j‘] + 1;同时更新j‘ = 3;(如果还不相等,就再次找r的最大边界,指导j更新为0)

代码


preprocessing的代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

vector<int> kmpProcess(string s) {

        vector<int> b(s.size(),0);

        int j = 0;

        //下面计算b[i]

        for (int i = 1; i < s.size(); i++) {

            while (j > 0 && s[i] != s[j]) 

                j = b[j - 1];//当前的widest border不满足要求,那么找到next widest border

            if (s[i] == s[j]) 

                j++;

            b[i] = j;

        }

        return b;

    }

null

时间: 2024-10-03 22:39:06

Knuth-Morris-Pratt Algorithm的相关文章

模板: 字符串模式匹配 Knuth–Morris–Pratt Algorithm

Knuth–Morris–Pratt Algorithm KMP字符串模式匹配算法 模板题 Brief Introduction To be updated Algorithm To be updated Template Code #include <cstdio> #include <cstring> #define MAXN 1000005 int n,m,cnt,next[MAXN]; char s1[MAXN],s2[MAXN]; void kmp(){ next[0]=

KMP(Knuth–Morris–Pratt) Algorithm

文章 String S, 要查找的字符串 String W 重点:Get int T[] from W 用变量 c 来表示当前比较到的 W 中前面的字符,i 表示当前要处理的 T 中的 index,int[] T = new int[W.length];T[0] = -1; T[1] = 0;c=0; i=2 example:array:    a    b    a    b    c    d    a    b    a    b    a    bidx    :    0    1  

我所理解的 KMP(Knuth–Morris–Pratt) 算法

假设要在 haystack 中匹配 needle . 要理解 KMP 先需要理解两个概念 proper prefix 和 proper suffix,由于找到没有合适的翻译,暂时分别称真实前缀 和 真实后缀. 真实前缀(Proper prefix): 一个字符串中至少不包含一个尾部字符的前缀字符串.例如 "Snape" 的全部真实前缀是 “S”, “Sn”, “Sna”, and “Snap” . 真实后缀(Proper suffix): 一个字符串中至少不包含一个头部字符的后缀字符串

Go语言(golang)开源项目大全

转http://www.open-open.com/lib/view/open1396063913278.html内容目录Astronomy构建工具缓存云计算命令行选项解析器命令行工具压缩配置文件解析器控制台用户界面加密数据处理数据结构数据库和存储开发工具分布式/网格计算文档编辑器Encodings and Character SetsGamesGISGo ImplementationsGraphics and AudioGUIs and Widget ToolkitsHardwareLangu

GO语言的开源库

Indexes and search engines These sites provide indexes and search engines for Go packages: godoc.org gowalker gosearch Sourcegraph Contributing To edit this page you must be a contributor to the go-wiki project. To get contributor access, send mail t

[转]Go语言(golang)开源项目大全

内容目录 Astronomy 构建工具 缓存 云计算 命令行选项解析器 命令行工具 压缩 配置文件解析器 控制台用户界面 加密 数据处理 数据结构 数据库和存储 开发工具 分布式/网格计算 文档 编辑器 Encodings and Character Sets Games GIS Go Implementations Graphics and Audio GUIs and Widget Toolkits Hardware Language and Linguistics 日志 机器学习 Math

“浅析kmp算法”

"浅析kmp算法" By 钟桓 9月 16 2014 更新日期:9月 16 2014 文章目录 1. 暴力匹配: 2. 真前缀和真后缀,部分匹配值 3. 如何使用部分匹配值呢? 4. 寻找部分匹配值 5. 拓展 5.1. 最小覆盖字串 6. 参考资料 首先,KMP是一个字符串匹配算法,什么是字符串匹配呢?简单地说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道这个字符串里面是否有"ABCDABD":我想,你的脑海中马上就

省选前模板复习

PREFACE 也许是OI生涯最后一场正式比赛了,说是省选前模板,其实都是非常基础的东西,穿插了英文介绍和部分代码实现 祝各位参加JXOI2019的都加油吧 也希望今年JX能翻身,在国赛中夺金 数学知识 见数学知识小结 字符串 KMP算法Knuth-Morris-Pratt Algorithm KMP算法,又称模式匹配算法,是用来在一个文本串(text string)s中找到所有模式串(pattern)w出现的位置. 它是通过当失配(mismatch)发生时,模式串本身能提供足够的信息来决定下一

KMP算法解析(转自图灵社区)

KMP算法是一个很精妙的字符串算法,个人认为这个算法十分符合编程美学:十分简洁,而又极难理解.笔者算法学的很烂,所以接触到这个算法的时候也是一头雾水,去网上看各种帖子,发现写着各种KMP算法详解的转载帖子上面基本都会附上一句:“我也看的头晕”——这种诉苦声一片的错觉仿佛人生苦旅中找到知音,让我几乎放弃了这个算法的理解,准备把它直接记在脑海里了事. 但是后来在背了忘忘了背的反复过程中发现一个真理:任何对于算法的直接记忆都是徒劳无功的,基本上忘得比记的要快.后来看到刘未鹏先生的这篇文章:知其所以然(

字符串匹配:从后缀自动机到KMP

后缀自动机(sam)上的字符串匹配 ==== 我们把相对较短的模式串构造成sam. 对于P="abcabcacab", T[1..i]的后缀,使得它是sam的最长前缀长度: T: b a b c b a b c a b c a a b c a b c a b c a c a b  c 1 1 2 3 1 1 2 3 4 5 6 7 1 2 3 4 5 6 7 5 6 7 8 9 10 4 如果最长前缀长度是|P|,则表示T[1..i]的后缀和P匹配. 内存使用 可能多个trans指针同