一、开头
神犇MX:哈哈哈哈哈,xyz32768,又碰面了!再考你一道很水很水的题:给出一个长度为 n n ,只由小写英文字母组成的字符串,求这个字符串不同的子串个数,
,至少给出两种方法!
xyz32768:后后后后后缀数组, n(n+1)2 n ( n + 1 ) 2 减去 height h e i g h t 之和?
神犇MX:说得出第二种方法我就算你厉害。先提示你,第二种方法用到的算法名称是五个字,后面三个字是「自动机」。
xyz32768:啊……难道是,神犇自动机?还是蒟蒻自动机?
神犇MX:哈哈哈哈哈哈哈哈,都不是,是后缀自动机!后缀自动机是一种很水的数据结构,但只有像我这样比你强 109 10 9 倍的神犇才会后缀自动机!xyz32768你真是菜啊!
xyz32768:我本来就菜啊………………什么?后……后缀自动机?
二、引入
SAM的全称是Suffix Automaton,即后缀自动机。
后缀自动机是这样一种数据结构,对于一个字符串 S S ,后缀自动机能存下字符串
的所有后缀,即能识别字符串 S S 的所有后缀。同时,由于
的任意一个子串都是 S S 的后缀的前缀,所以从一定意义上后缀自动机还可以识别
的所有子串。一个朴素的想法是把 S S 的所有后缀建成一棵Trie树,Trie树中的点表示状态,Trie树中的边表示转移。
以字符串
为例(紫色节点表示一个后缀的终点):
状态数和转移数都是 O(n2) O ( n 2 ) 的。而后缀自动机是一个有向无环图,一个状态表示的字符串个数可能不止一个。后缀自动机运用了所有字符串都是 S S 的后缀这一特性,实现了
的时空复杂度。
下面是字符串 S=noiioi S = n o i i o i 的后缀自动机:
三、概念
Rights R i g h t s :子串 s s 的
集合,定义为子串 s s 在
中出现的末尾位置的集合。
举 2 2 个例子:
,则 Rightoi={
3,6} R i g h t o i = { 3 , 6 }
S=orzpyzorzlpforzcyx S = o r z p y z o r z l p f o r z c y x ,则 Rightorz={
3,9,15} R i g h t o r z = { 3 , 9 , 15 }
(字符串的位置下标从 1 1 开始)
一个状态表示的子串可能不止一个,但这些子串的
集完全相同。一个状态的 Right R i g h t 集就是这个状态表示的子串的 Right R i g h t 集。下面把状态 i i 的
集合也记为 Righti R i g h t i 。
Parenti P a r e n t i :满足 Righti⫋Rightj R i g h t i ⫋ R i g h t j 的 |Rightj| | R i g h t j | 最小的 j j (
和 j j 是状态)。也就是
集包含 Righ