回文树/回文自动机 引入

回文树/回文自动机引入

在介绍这种数据结构之前,我们来回顾一下处理字符串的一些武器:

         1.KMP、AC自动机

         2.后缀三姐妹(后缀树,后缀数组,后缀自动机)

         3.字符串hash

         4.字符串dp

         5.manacher算法

         6.暴力乱搞

 

其中,AC自动机和后缀自动机已经可以解决字符串的大部分问题,但在处理回文字符串类问题时略显不足。Manacher算法是一个非常专的算法,在遇到类似于公共回文子串的问题中没有太大优势。

在这种形势下,我们需要一种高效的处理回文字符串的武器。即回文树(回文自动机,Palindromic Tree),回文树是由俄罗斯人 MikhailRubinchik于2014年夏发明的(http://codeforces.com/blog/entry/13959),在原文中已有详细介绍与代码实现。

 



回文树由节点和边组成,严格来说它并不是一棵树,而且具有很多自动机的性质。在回文树中,每个节点代表一个回文字符串,如上图,请注意这些节点只会包含所有不同的回文子串,可以证明这些子串不超过n个(n为字符串总长)。边有两种,普通边和后缀链(失配边,suffix link)。若某个节点代表的回文串A两边加上某个字母X形成新回文串B,则A到B之间有边X(图中蓝色)。一个回文串的后缀链(图中红色)指向它最大后缀回文串(不包括它本身)。

 

以上是回文树的基本定义。请注意实际使用时节点内不会存储实际的字符串,只要知道它的长度和两头的字母就可以了。

 

下面我们来尝试递归构造一个回文树:

        

         1.新建节点E和S,E代表空串,E的长度为0,所有一个字母的节点的后缀链都会指向它,S代表“根”节点,S的长度为-1(为了之后运算方便),从E到S有后缀链。

         2.我们从第一个字母开始逐个构造,假设构造好了字符串P的回文树,P是原串前缀。下一个待构造字母是x,变量last指向上一个构造的回文子串的节点。

         3.x加上last串后可以得到一个******x的串,这个串第一个字母如果是x,那么可直接进行步骤4,否则沿着后缀链走(可以走到下一个后缀是回文串的节点,注意之前的定义),得到之后的***x,直到形成类似x***x的回文串。这个过程结束。

         4.如果上述过程找到的x****x中的****已经有一条边F(x),则说明该串已经出现过,不做任何处理,否则要为该串设置新的后缀链和F(x),F(x)的设置方法很明显,后缀链则继续3的寻找过程,找到下一个x*x即可(此时空串节点发挥了作用,因为单个字母一定是回文串,继续寻找就是空串)。然后设置后缀链,更新last。问题此时又回到了2.。

 

在步骤3中,我们找到了一个x*****x的回文字符串,如果它之前已经出现过,我们就直接跳过步骤4了,不再继续寻找其余的比它短的x**x。如何证明它如果之前出现过,那么它的后缀的x**x结构也出现过呢?很简单,根据对称性,后缀有的东西前缀也有,所以前缀已经出现过x**x,问题得证。

 

如果理解了回文树的构造过程,我们会发现它和后缀自动机的构造类似。后缀自动机的节点代表后缀,回文树的节点代表回文串。实际上,回文树就是“在两头加字母”的后缀自动机。此外,回文树的时间复杂度是O(字母集*n),也与后缀自动机一致。

 

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值