字符串匹配算法

Download Report

Transcript 字符串匹配算法

第六章
字符串处理算法
邹权(博士)
计算机科学系
提要
6.1 问题介绍
6.2 Z-box算法
6.3 BM算法
6.4 KMP算法
6.5 关键字树
6.6 后缀树
6.1 问题介绍
• 问题提出:字符串精确匹配(Exact String
Matching)问题可以描述如下:给定一个
长字符串T和一个短字符串P,其中它们的
长度分别是|T|=m, |P|=n,利用最理想的时
间和空间找出全部的T中与P完全匹配的子
串。
• 习惯的表示方法:字符串T/P中的第i个字符
用T(i)来表示。
6.2 Z-box算法
• [定义]Zi(S)表示在字符串S中从第i位起
与S的前缀匹配的最长的字符串的长
度。(数值)
• 注:如果S在上下文中很明显,Zi(S)可
以用Zi来表示。
• 例:S=a a b c a a b x a a z 那么
12345678
• Z5(S)=3; Z6=1;Z7= Z8=0
• Z-box:其中每个与前缀匹配的子串就
叫一个Z-box。对于任意数字i,如果S
(i)属于某一个Z-box,则定义Li表示
该Z-box的最左端的位置,Ri表示该Zbox的最右端的位置。
• 例:在上例中L6=5 R6=7
• 性质:if i>j,then Ri>=Rj
• [任务] 在线性时间内
(O|S|)计算S的所有Zi
• [思想] Z2正常计算,然后
归纳计算Zk,可以减少比
较的次数
• [思想]令S=P$T,其中$是特殊字符,在S和
T中都不存在。利用Z算法计算Zi(S)。
• [方案]对于任意j,如果Zn+1+j(S)=n,则P出
现在T(j)处。
• [加强]因为$的设定,对于任意i都有Zi<n,
即k`总落在P内,所以当k>n时(即在T
中)Zk值不用计算,只需要维持
(maintain)R和L的值。
6.3 BM算法
• [名称] Boyer-Moore算法
• [特点]从左向右移动,自右向左扫
描
• [技巧]坏字符规则
好后缀规则
6.3.1 坏字符规则
• [实质]把P中的坏字符x移到T中的x的
下面
• [定义] 对于字母表中的每一个字符x,
R(x)表示x在P中的最右端的位置,如
果P中没有x,则R(x)=0。
• [规则]对于P和T,如果P右面的n-i个字
符都和T匹配,但是P(i) ≠T(k)。那么P
可以向右移动max[1,i-R(T(k)]位。
1234567890
• [例] T= x p b c t b x a b p q x
P=
tpabxab
• 因为P(3)!=T(5),R(T(5))=R(t)=1
max[1,3- R(T(5))]=2
• 所以P可以向右移动2位,然后
再从右向左依次同T比较
6.3.1 坏字符规则
• 普通坏字符规则有局限性:
1.不适合简单字母表 (DNA匹配)
2.不适合有大量重复子串的P (蛋白质
匹配)
• 加强规则:当P(i) ≠T(k)时,如果
T(k)=x,将P中位置i左面最近的x移到
T(k)下面。(更好的体现了坏字符规则
的精神)。
• 相关讨论:普通的坏字符规则节省空
间,它只需要O|∑|(∑是字母表)的空
间存放R(x)(R(x)是一个数组);而加强
坏字符规则可能需要更大的空间。
• 解决办法:可以不用二维数组,用一
维数组,其中一维数组中的每个元素
是一个数的序列。如:P=abacbabc 那
么R(a)=6,3,1 所需空间O(n)
6.3.2 好后缀规则
• 坏字符规则的局限:
1.不适合小字母表
2.最差运行时间不是线性的
• 思想:看准T中的子串t,看P中还有没
有子串匹配t
• 区别:坏字符规则是去匹配T中的一个
坏字符;好后缀规则是去匹配T中的一
个子串
• 规则:给定P、T,T的子串匹配了
P的一个后缀,但是再往左一个字
符就不匹配了。然后寻找t`:
1. t`和t相同
2. t`不是P的后缀
3. t`左面的那个字符同与t匹配的
P的后缀的左面那个字符不相同。
• 将P向右移,直到t`位于t的下面。
• 如果t`不存在,则将P向右移动最少
的格数使:P的前缀同t的后缀相匹
配。
• 如果这种情况也不存在,那么将P
向后移动n位。
• 如果T中发现了一个P,将P向右移
动最少格数使:P的前缀能够和T中
发现的P的后缀相匹配。如果没有
这种匹配,则将P向后移动n位。
•例1 2 3 4
T
p r s t
P
q c
1 2
5
a
a
3
6
b
b
4
7
s
d
5
8
t
a
6
9
u
b
7
0
b
d
8
1
a
a
9
2 3 4
b v q x r
b
0
• 因为P(8)!=T(10),t=ab,又因为t`
在P中开始的位置是3,所以P向右
移动6步
• [对比]在本例中,坏字符规则只能
使P向右移动1步
6.4 KMP算法
• [名称] Knuth-Morris-Pratt算法
• [特点]从左向右移动,从左向右比
较
• [定义]对于P中的每个位置i, spi(P)为P[1...i]
中最长后缀的长度,该后缀与P的一个前
缀匹配[数值]
• [注]对于任意串sp1=0
• [例] 1 2 3 4 5 6 7 8 9 0 1
P= a b c a e a b c a b d
sp2=sp3=0; sp4=1; sp8=3; sp10=2
• [定义]对于P中的每个位置i ,spi`(P)为
P[1...i]中最长后缀的长度,该后缀与P的一
个前缀匹配,并且P(i+1)≠P(sp`i+1)
• [例]上例中sp`8=0, sp`9=4
• [转移规则] 对于P和T,如果P(i+1)≠T(k),
则将P[1…sp`i]移到T[k- sp`i...k-1]下面,也
就是将P向右移了i- sp`i步,然后比较
P(sp`i+1)和T(k);如果发现了一个P在T
中,将P向右移动n-sp`n步
• [优点]移动之后,前sp`个字符不用再比较
了,直接比较P(sp`i+1)和T(k)就可以了
• [定理]在Knuth-Morris-Pratt算法中,字符
比较的次数最多是2m
• [real-time]对于T的任意位置,如果第
一次检测它,也就是最后一次检测它
(就是说对每一位最多只比较一
次),则说它是real-time.
• [意义]1. 对于一个小内存机器,在下一
个字符读入之前,要保证上一个字符
已经处理完毕。
2. 在确定的实例中,real-time方
法应该运行的更快一些。
• Knuth-Morris-Pratt算法不是real-time
的。因为对于不匹配的位置,还至少
要再比较一次。
• 如何 把Knuth-Morris-Pratt算法转变成
一个real-time方法?
• [定义]x是字母表中的一个字符,
sp`(i,x)(P)=sp`i(P)并且P(sp`i+1)=x
• [思想]P同T进行比较,T(k)=x处与
P(i+1)不匹配,那么P向右移动isp`(i,x)步。这样T(k)=P(sp`(i,x)+1)=x
不用比较,直接比较P(sp`(i,x)+2)和
T(k+1)即可。显然这种方法是realtime的.
6.5 关键字树
• [目标]在一个目标序列中搜索多个
查询序列的完全匹配
• [算法] Aho-Corasick算法
• [数据结构]关键字树
[定义]集合P的关键字树(keyword
tree)是一棵有根树,它的根记为K,
满足
1. 每一条边都标定一个字母
2. 从同一结点分开的任意两条边对应
着不同的字母
3. 每一个字符串Pi都对应着一个结点
v,从树根K出发到达v的路径可以恰好
正确地拼出字符串Pi,并且树K的每一
个叶结点都对应P的某一个模式。
P={potato,poetry,pottery,science,school}的关键字树
• 很容易看出构造一颗关键字树的时间
复杂性是O(n)。
• 关键字树建立起来以后,对于普通的
搜索方法时间复杂性是O(mb),其中
b=max|Pi|。然而,我们可以利用失效
链接(failure link)技术来加速搜索过
程。
• 失效链接的前提是在P中不存在一个模
式是另一个模式的子串!
• 定义1:L(v)表示从根结点到结点v的
字符连接起来得到的字符串。
• 定义2:lp(v)表示L(v)中最长后缀的
长度,该后缀是P中某个模式的前
缀。(数值)
L(v)=potat
lp(v)=|tat|=3
• 定义3 :α表示字符串L(v)的长为
lp(v)的后缀,那么在关键字树中有
唯一的结点标定α。该唯一的结点
记为nv。当lp(v)=0时,nv就是跟节
点K。
• 定义4:有序对(v,nv)称为一个失效
链接.
• 失效链接的建立算法的关键是在线
性时间内得到所有的失效链接,可
以采用归纳的思想:若v是根r,或
v是r的儿子,则nv=r;假设距根结
点的距离小于等于k的所有的结点v
的nv都已经计算出来,我们现在计
算据r的距离为k+1的结点v的nv.
• 假设所求的结点为v(距r为k+1的结
点),他的父亲是v’,v’到v这条边所
标定的字母是x,
①若nv’的下一个字符有x,则设该边的
另一个结点为w’,即有nv=w’
②若nv’到它所有儿子的边所标定的字母
均不是x,则字符串L(nv)(表示从根结
点到nv所标定的字符串)是L(nv’)的一个
后缀跟上x,又因为该后缀与根结点开
始的字符串匹配(类似前缀)所以可
以检测 后面是否有x,如果没有则继续
下去。
• 该算法的主要思想是将集合P构造成一
棵关键字树,利用Aho-Corasick算法
和失效链接在线性时间内完成搜索。
该算法的时间复杂性是O(m+n+k),其
中k为P在T中出现的次数。其中预处
理阶段的时间复杂性是O(n),搜索阶段
的时间复杂性是O(m+k)
6.6 后缀树
给定长度为n的字符串S, S的后缀
树是一颗有n个叶子结点的树。树中
的每一条边上都标识着字符串S的一
个非空子串。由根结点开始到任何一
个叶子结点的路径上所有的标识连接
起来构成的字符串对应着字符串S的
某一个后缀。由同一结点发出的任何
两条边上所标识的字符串的首字符不
允许相同。
字符串BANANAS的后缀树
• 构造后缀树所需要的时间和空间都
是线性于字符串长度的,这也是后
缀树得到广泛应用的原因之一。经
典的后缀树构造算法有两种,分别
是MCC算法和UKK算法。
6.6.1 后缀树应用——字符串精确匹配
• P和T同时已知:利用后缀树和BM
算法是等效的。
• P已知、固定,T不固定:利用BM
算法或KMP算法即可,后缀树叶可
以在同样的时间内完成。
• T已知、固定,P不固定:可以先对T
进行预处理,然后每输入一个P利用后
缀树在O(n+k)时间内找出所有的P(其
中|P|=n,k是P在T中出现的次数)。
这也是后缀树优于其他算法之所在。
• 这类问题称为子串问题,一个典型的
应用是在DNA数据库中,比如输入一
段DNA序列,我们想知道该序列在我
们的DNA数据库中是否已经存在。
6.6.2后缀树应用——最长公共子串
• 将S1和S2建立到一颗后缀树中,这种融入
了多个字符串的后缀树称为广义后缀树。
具体思想如下:对于每一个叶节点,如果
它标定的字符串(从根节点到该节节点的
路径上的字符串)是S1的后缀,则给他一
个标记flag=1;如果一个叶节点标定的字符
串是S2的后缀则它的标记flag=2。那么同时
具有两种叶节点为后代的内部节点所标定
的字符串就是公共子串。那么找出最深的
这样的内部节点即可。
• 后缀树的缺点
–不容易on line
–不容易处理大规模数据
• 字符串(String)=序列(Sequence)
• 子字符串VS子序列
• 最长公共子串VS最长公共子序列
(LCS)
• 后缀树VS动态规划
小结
[Z算法]线性时间解决问题
[Knuth-Morris-Pratt算法]
1.可以扩展到Aho-Corasick算法,用来在O(m)时间
内解决搜索P的集合。
2.当T是在线输入的(on-line)具有很好的扩展
性,可以加强到real-time
[Boyer-Moore算法]最差搜索时间是线性的,期望
搜索时间是亚线性的(sublinear time)
[后缀树算法]
1.预处理T,而不是P,搜索时间是O(n)的
2.解决一些更复杂问题,其中相当一部分是前面几
个算法无法处理的