字符串匹配:从机器到后缀自己主动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指针同一个节点。因此像删除树那样会引起double-free:

为此我们临时採用内存池的做法。

假设扩展到包含数字和空格,则须要表示37个转移指针。

KMP算法

====

给定模式串P,文本串T,

如果在s位置已匹配了q个字符, 即P[1,..,q]=T[s+1,..,s+q], 而在P[q+1]不匹配。

strstr()这时会把指针指向s+2,从P[1]又一次開始匹配。

当时Knuth,Morris,Pratt就想可不能够把指针再移远一点。

如果有P[1,..,k]=T[s+q+1-k,..,s+q],这时从P[k+1]開始比即可了,显然我们希望k越大越好,相应地指针移动增量=q-k越小,因此应该不会错过某些全然匹配的位置。

我们把上面两个等式合并,得到P[1,..,k]是P[1,..,q]的后缀。

问题变成:

对于每一个q, 求P[1,..,q]的最长的真前缀(长度记为k),同一时候它也是P[1,..,q]的后缀。

我们定义前缀函数pi(q):=k.

怎样计算pi(q) ?

====

使用递推的想法,如果我们已经计算好了pi(q)=k。

假设P[k+1] = P[q+1], 则显然有pi(q+1) = k+1;

否则,看作是一个匹配问题, 我们来看pi(q)的含义是与P[1,..,q]末尾匹配的最长前缀长度k,我们就拿这个前缀来匹配,并期望P[k+1]和P[q+1]一样,否则k=pi(k)循环下去。

初始条件:pi(1) = 0, 由于最长真前缀是空串。

当前P[1,..,k]匹配T[q-k+1,q],而在T[q+1]不匹配。

应用前缀函数的定义。应该从位置s+1-k + q-k =

一个字符串P[1,..,j]去匹配P[q+1-j,..q+1]的过程。

k=pi(k), 直到P[k] = P[q+1]。

怎样做线性的字符串匹配?

====

參照后缀自己主动机的做法, 我们把pi和P组成一个自己主动机,T在这个自己主动机上

走一遍。

前缀函数练习题目:

1. P 在T中的出现次数? 提示:检查pi(PT)

2. (ab)^3 = ababab, 怎样求最大的反复因子r=3?

3. 怎样在线性时间内推断是否为循环移位,比方arc和car。(这个我还不知道怎么做)

KMP比SAM节省内存:

版权声明:本文博客原创文章。博客,未经同意,不得转载。

时间: 2024-11-02 09:26:49

字符串匹配:从机器到后缀自己主动KMP的相关文章

字符串匹配的算法(暴力算法和KMP算法)

学习字符串匹配算法有一段时间了,不过还是有点迷糊,虽然了解算法过程,但是在编码的时候还是会有些迷糊. 先把写的程序放在这里,以后有时间再来翻着看看吧! #include<iostream> #include<string> using namespace std; int KMPfind(char* s, char* p); void GetNext(char* p, int next[]); int ViolentMatch(char* s, char* p); int main

字符串匹配相关模板(字典树、KMP、AC自动机)

字典树 struct Trie { int ch[MAXN][26]; int cnt; Trie() { cnt=1; memset(ch[0],0,sizeof(ch[0])); } int idx(char c) { return c-'a'; } void insert(char *s,int v) { int u=0,len=strlen(s); for (int i=0;i<len;i++) { int c=idx(s[i]); if (!ch[u][c]) { memset(ch[

字符串匹配:从后缀自动机到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指针同

字符串匹配的KMP算法

html, body { font-size: 15px; } body { font-family: Helvetica, "Hiragino Sans GB", 微软雅黑, "Microsoft YaHei UI", SimSun, SimHei, arial, sans-serif; line-height: 1.6; color: ; background-color: ; margin: 0; padding: 16px 20px; } h1, h2, h

字符串匹配与KMP算法笔记

>>字符串匹配问题 字符串匹配问题即在匹配串中寻找模式串是否出现, 首先想到的是使用暴力破解,也就是Brute Force(BF或蛮力搜索) 算法,将匹配串和模式串左对齐,然后从左向右一个一个进行比较, 如果不成功则模式串向右移动一个单位,直到匹配成功或者到达匹配串最后仍然不成功,返回失败. 很明显,这种算法有很多的地方可以优化,假设要搜索的串为S,长度为n,要匹配的串为M,长度为m,时间复杂度为O(nm). >>KMP算法 Knuth-Morris-Pratt算法以三个发明者命名

字符串匹配的KMP算法(转)

字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 许多算法可以完成这个任务,Knuth-Morris-Pratt算法(简称KMP)是最常用的之一.它以三个发明者命名,起头的那个K就是著名科学家Donald Knuth. 这种算法不太容易理解,网上有很多解释,但读起来都很费劲.直到读到Jake Boxer的文章,我才真正理解这种算法.下面,我用自己的语言

[CLRS][CH 32]字符串匹配

问题简介 对于给定文本 T[n] 和模式 P[m],找到一个位移量 s,使得 T[s + j] = P[j] (0 <= s <= n-m, 1 <= j <= m),则说明模式 P 在文本 T 中出现且位移为 s.所以字符串问题就是在给定文本 T 中,找出指定模式 P 出现的所有有效位移的问题. 记号和术语 长度为0的空字符串用 ? 表示.字符串 x 的长度用 |x| 表示.字符串 x, y 的连接表示为xy,长度为 |x|+|y|.对于字符串 x, y, w,如果 x = wy

字符串匹配KMP算法C++代码实现

看到了一篇关于<字符串匹配的KMP算法>(见下文)的介绍,地址:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html,这篇博客对KMP算法的解释很清晰,但缺点是没有代码的实现.所以本人根据这位大神的思路写了一下算法的C++实现. C++代码如下: #include <iostream> #include<string.h> using namesp

【算法】字符串匹配之Z算法

在很长一段时间,求文本与单模式串匹配,我只用KMP.后来我在CF上看到Z算法,用的人也不少.在学习之后,我感觉Z算法也是很精妙的.在以前的博文中也有过用Z算法来解决字符串匹配的题目. 下面介绍一下Z算法. 先一句话讲清楚Z算法能求什么东西. 输入为一个字符串s,Z算法可以求出这个字符串每一个后缀与自身的最长公共前缀LCP. 接下来,介绍Z算法的具体内容. 记字符串s的长度为n. Z算法需要维护一对值,记为left和right,简记为L和R.L和R满足s[L,R]为s串的前缀.当i为1的时候,暴力