《柔性字符串匹配》读书笔记(1)之--KMP算法(单模式串匹配、前缀匹配)
来源:互联网 发布:2017淘宝直通车 编辑:程序博客网 时间:2024/06/10 09:39
——by m4trix
《柔性字符串匹配》: 《Flexible Pattern Matching in Strings》
KMP算法: Knuth-Morris-Pratt algorithm
Knuth is Donald Knuth, you know the guy I mean.
KMP算法: Knuth-Morris-Pratt algorithm
Knuth is Donald Knuth, you know the guy I mean.
所谓字符串匹配:给出两个字符串A,B,回答B串是否是A串的子串(A串是否包含B串)。这里称A为文本,B为模式,即要回答模式B是否为文本A的子串。
有:
文本 A = t1t 2t3...t n
文本 A = t1t 2t3...t n
模式 B = p1p 2p3...p m
传统的字符串匹配算法:(算法时间复杂度O((n-m+1)*m))
把文本A中位移分别0,1,...n-m时的文本(t1 t2t 3...tm, t 2t 3t 4...t m+1, t 3t 4t 5...t m+2, ...)依次跟模式B进行比较,查找匹配与否。
这种算法没有对已匹配过的信息加以利用,KMP算法就是在充分利用已匹配信息的基础上,来避免一些明显的不合理的移位(每次当t xt x+1t x+2...t x+m-1与模式B不匹配时,需要对文本A后移一位t x+1t x+2t x+3...t x+m-2来继续进行对比,其实有的时候可以一次移z(z>1)位,这样子效率更优)。那么问题来了:KMP是怎么来对已匹配信息加以利用的呢,每次不匹配了需要对文本移位再比较时,移多少位呢,怎么确定:
KMP算法的思想:(算法最坏时间复杂度O(n),平均时间复杂度O(n))
一些概念:
部分匹配表(Partial Match Table):所谓部分匹配表,即模式B中当匹配到第i个字符时,在p1p 2p3 ...p i中,既是该串的前缀、同时又是该串的后缀的最长字符串的长度与索引i的一个映射关系表。
部分匹配表(Partial Match Table):所谓部分匹配表,即模式B中当匹配到第i个字符时,在p1p 2p3 ...p i中,既是该串的前缀、同时又是该串的后缀的最长字符串的长度与索引i的一个映射关系表。
如有模式串:"abababca"
则有部分匹配表:
如何计算得来:
- "a"的前缀和后缀都为空集,因此公共元素的最大长度为0;
- "ab"有前缀["a"], 后缀["b"], 公共元素的最大长度为0;
- "aba"有前缀["a", "ab"], 后缀["ba", "a"], 公共元素"a"的最大长度为1;
- "abab"有前缀["a", "ab", "aba"], 后缀["bab", "ab", "b"], 公共元素"ab"的最大长度为2;
- "ababa"有前缀["a", "ab", "aba", "abab"], 后缀["baba", "aba", "ba", "a"], 公共元素"a", "aba"的最大长度为3;
- "ababab"有前缀["a", "ab", "aba", "abab", "ababa"], 后缀["babab", "abab", "bab", "ab", "b"], 公共元素"ab", "abab"的最大长度为4;
- "abababc"有前缀["a", "ab", "aba", "abab", "ababa", "ababab"], 后缀["bababc", "ababc", "babc", "abc", "bc", "c"], 公共元素的最大长度为0;
- "abababca"有前缀["a", "ab", "aba", "abab", "ababa", "ababab", "abababc"], 后缀["bababca", "ababca", "babca", "abca", "bca", "ca", "a"], 公共元素"a"的长度为1;
部分匹配长度(partial_match_length):所谓部分匹配长度,即文本A中的子串与模式B中的前i个字符相匹配,第i+1个字符不匹配,则此时的部分匹配长度为i.
有了部分匹配表和部分匹配长度,KMP算法对其怎么加以利用:
当文本A中的子串部分匹配模式B时,有部分匹配长度:partial_match_length, 部分匹配表PMTable, 则当PMTable[partial_match_length] > 1, 则文本A向前位移 partial_match_length - PMTable[partial_match_length - 1]长度,继续用子串与模式B来匹配,依次循环,直到匹配上或者直至文本A走完为止。
当文本A中的子串部分匹配模式B时,有部分匹配长度:partial_match_length, 部分匹配表PMTable, 则当PMTable[partial_match_length] > 1, 则文本A向前位移 partial_match_length - PMTable[partial_match_length - 1]长度,继续用子串与模式B来匹配,依次循环,直到匹配上或者直至文本A走完为止。
综上,KMP分两步来完成:
1、对模式串进行预处理,计算出部分匹配表;
2、依据Partial Match Table,对文本进行跳跃式位移来拿文本子串和模式进行匹配。
示例:
文本A:"bacbababaabcbab"
模式B:"abababca"
1、
如上图:
没有部分匹配中,文本A向前移1位;
2、
如上图:
部分匹配,有partial_match_length = 1,
根据:
if (PMTable[partial_match_length] > 1) {
文本A向前移partial_match_length - PMTable[partial_match_length - 1]长度;
} else {
文本A向前移 1 位;
}
PMTable[1] = 0 < 1,
文本A向前移1位;
3、
如上图:
没有部分匹配中,文本A向前移1位;
4、
如上图:
没有部分匹配中,文本A向前移1位;
5、
如上图:
部分匹配,有partial_match_length = 5,
PMTable[5] = 4 > 1, partial_match_length - PMTable[partial_match_length - 1] = 5 - PMTable[5 - 1] = 5 - 3 = 2,
文本A向前移2位;
6、
如上图:
部分匹配,有partial_match_length = 3,
PMTable[3] = 2 > 1, partial_match_length - PMTable[partial_match_length - 1] = 3 - PMTable[3 - 1] =3 - 1 = 2,
文本A向前移2位;
7、
如上图:
模式的长度已经超出了剩余的子文本串的长度了,因此匹配结束,没有匹配中。
模式的长度已经超出了剩余的子文本串的长度了,因此匹配结束,没有匹配中。
C代码实现:
KMP算法的适用场景:
因为KMP算法是对模式串进行预处理,因此该算法非常适合求解这样的问题:
给定一个模式串B,和一群文本A串,问B是哪些A串的子串。
<span style="font-size:18px;">/* * input: x is the pattern string * input: m is the length of pattern string * output: KMPNext is the Partial Match Table */void preKMP(char *x, int m, int KMPNext[]){ int i, j; i = 0; j = KMPNext[0] = -1; while (i < m) { while (j > -1 && x[i] != x[j]) { j = KMPNext[j]; } i++; j++; if (x[i] == x[j]) { KMPNext[i] = KMPNext[j]; } else { KMPNext[i] = j; } }}void KMP(char *x, int m, char *y, int n){ int i, j, KMPNext[XSIZE]; /* Preprocessing */ preKMP(x, m, KMPNext); /* Searching */ i = j = 0; while (j < n) { while (i > -1 && x[i] != y[j]) { i = KMPNext[i]; } i++; j++; if (i >= m) { //OUTPUT(j - i); i = KMPNext[i]; } }}</span>
KMP算法的适用场景:
因为KMP算法是对模式串进行预处理,因此该算法非常适合求解这样的问题:
给定一个模式串B,和一群文本A串,问B是哪些A串的子串。
Refer:
"The Knuth-Morris-Pratt Algorithm in my own words"
http://jakeboxer.com/blog/2009/12/13/the-knuth-morris-pratt-algorithm-in-my-own-words/
http://jakeboxer.com/blog/2009/12/13/the-knuth-morris-pratt-algorithm-in-my-own-words/
"KMP算法详解"
http://blog.csdn.net/yutianzuijin/article/details/11954939
"Knuth-Morris-Pratt algorithm description and C code by Christian Charras and Thierry Lecroq"
http://www-igm.univ-mlv.fr/~lecroq/string/node8.html
http://www-igm.univ-mlv.fr/~lecroq/string/node8.html
0 0
- 《柔性字符串匹配》读书笔记(1)之--KMP算法(单模式串匹配、前缀匹配)
- 《柔性字符串匹配》读书笔记(2)之--AC算法(多模式串匹配、前缀匹配)
- 《柔性字符串匹配》读书笔记
- 字符串匹配(模式匹配)KMP BM
- KMP(单模式匹配)
- 关于字符串匹配(单模式匹配)的各种算法
- 模式匹配之(BF KMP算法)
- KMP算法-字符串匹配
- 字符串匹配(KMP算法)
- 字符串匹配算法(KMP)
- kmp算法(字符串匹配)
- 字符串匹配(KMP算法)
- KMP算法(字符串匹配)
- 字符串匹配(KMP算法)
- 数据结构 字符串模式匹配之KMP算法
- 字符串匹配的KMP算法(部分匹配表:前缀---后缀)
- 简单讲解KMP单模式匹配与AC算法多模式匹配(KMP篇)
- 字符串模式匹配KMP算法
- leetcode 28 -- Implement strStr()
- windowns里ntfs下分区的目录如何在linux下smb共享--2006-10-19 博客搬家
- org.apache.subversion.javahl.ClientException: svn: E155021: This client is too old to work with the
- #leetcode#Longest Consecutive Sqeuence
- 拉面
- 《柔性字符串匹配》读书笔记(1)之--KMP算法(单模式串匹配、前缀匹配)
- 第七课,分支结构程序体验|三个整数输出最大值 |计算两数正差值|周薪计算
- 在QML的UbuntuApplication Context Property
- 嵌入式Linux系统图形及图形用户界面综述--2005-04-20博客搬家
- linq读写dt
- android删除文件出错
- erlang 压力测试工具 tsung
- Axure实现淡入淡出效果
- Android加载图片导致内存溢出(Out of Memory异常)