——————《高级数据结构》
在这一节中,我们将给出几个常见的后缀树的应用,并且你将会看到它与其他处理字符串的算法与数据结构(例如KMP算法,AC自动机等)之间的比较。后缀树是一个非常强大的处理字符串问题的工具,并且企图在这一节短篇幅里面穷尽其应用是不可能的。因此,这里的介绍旨在抛砖引玉,更多的应用可以参考相关的书籍以及该领域的最新研究成果。
字符串的精确匹配
情形一:
给定两个串S和T,分别代表模式串和文本串,长度分别为n和m,现在需要在串T中查找串P的每一个出现的位置。
了解KMP算法的读者一定对这个问题非常熟悉——这正是KMP算法应用的经典场景。在比较两者之前我们先看一下后缀树的算法实现。。
后缀树实现:首先构建串T的后缀树,所用时间复杂度为O(m),然后我们只需要在后缀树中查找串S即可。如果串S没有出现在后缀树中,那么显然串T不包含串S;如果串S结束于后缀树的某个节点v(结束于某一条边内的情形也类似),那么节点v的路径标记在T中出现的每个位置都匹配串S。为了知道所有出现的位置,我们只需要遍历v的子树,找到所有叶节点,便可以知道所有对应位置出现的位置了。当然,我们还有优化的余地——如果我们能够较快的找到v的字数中所有叶节点的话,就能够将查询降到O(n+k),其中k为S在T中出现的次数,也就是节点v子树中叶节点的个数,这正是一个于KMP一样优秀的时间复杂度。实现方式也很简单,将叶节点按照便利顺序额外用链表依次连接,每个内部节点只需标记叶节点的范围即可(肯定是连续的一段)。
伪代码:
Function FindMatches(S)
{
v<-Fin