后缀自动机
1.1 基本定义与概念
首先,来看看wikiEn的定义:
In computer science, a suffix automaton is the smallest partial deterministic finite automaton that recognizes the set of suffixes of a given string. The state graph of the suffix automaton without designated(特定的) accepting or rejecting states is called the directed acyclic(无环的) word graph (DAWG).
其次,来看看强大的论文是怎么说的:
简明定义:
对给定字符串s的后缀自动机是一个最小化确定有限状态自动机,它能够接收字符串s的所有后缀.
好吧,其实就是WikiEn第一句话的翻译~这篇论文实在是太强大了(虽然翻译是非常有问题的!所以应了我们高中老师说的话啊,有能力一定要看原版).下面是我读完并结合一些其他博客的见解.
形式定义:
后缀自动机拥有一个初始状态 (简记为 ),它能够到达所有其他的状态.
自动机中的所有转移——即有向边——都被某种符号(即该中字符串的字典符号)标记.从起始状态出发的诸转移的标记组成必须不同.
如果我们从初始状态t_0经由任意路径走到某一状态,并顺序写出所有经过边的标记,所得到的字符串必然是s的某一后缀,则称这些状态为终止状态.
对于论文中的简明定义,恰好要求了后缀自动机的一个重要性质.
在完成上述形式定义的所有自动机中,后缀自动机有最少的顶点数(边数并非最少).
随意给出两个例子:
从左往右依次记为状态
,则
从左往右依次记为状态
,下面则是
,则
同时由上可以看见:
任意时刻的最长路为直径,表示主串和最长后缀.(没有卵用的性质)
1.2 相关定义与概念
映射set endpos(state t)
对于这样一个映射
是后缀自动机的状态集合,记关系
,则该关系是等价关系.
证明:这样思考:在构建自动机的时候,每个状态都能对应一些字符串中的位置,而位置是有限,并且对应唯一一组子串使得这些子串的结束位置均为某一些特定位置。把状态对应下标整数,由字符串后缀的性质,,显然
是等价关系.
如果还不懂可以继续看下面一段话。
在做hihocoder的题的时候,我还是没有弄懂
的实质,于是我就问我们字符串专题的主讲wyy。确实是一语点醒梦中人了:来看看hihocoder给的例子
对于字符串aabbabd
状态 | 子串 | endpos |
---|---|---|
S | 空串 | {0,1,2,3,4,5,6} |
1 | a | {1,2,5} |
2 | aa | {2} |
3 | aab | {3} |
4 | aabb,abb,bb | {4} |
5 | b | {3,4,6} |
6 | aabba,abba,bba,ba | {5} |
7 | aabbab,abbab,bbab,bab | {6} |
8 | ab | {3,6} |
9 | aabbabd,abbabd,bbabd,babd,abd,bd,d | {7} |
先抛开
的概念,看看所有子串在字符串中的情况。显然空串可以是每一个地方都不取任何字符,所以空串的
是
,接下来再举一个例子,
的在字符串中出现的位置是
,所以
就是该集合。
那么为什么说endpos对应状态的集合呢?因为每一个状态对应一组子串,然后子串再对应字符串下标的集合QAQ,个人脑补就是这样。如果你们之前没用弄懂
是什么玩意,然后看了我这段话稍微有那么一点清楚了,那我就很高兴了。(应该不会有人比我更笨了…)
两个非空子串 和 ( )是终点等价的,当且仅当v在字符串s中仅作为u的后缀出现.
证明:充分性:由后缀自动机的性质, 定然是某一由起始状态到终点状态 路径的子路径 的某一路径的”后缀”, 是某一状态,由于后缀自动机构造使得路径具有唯一性,要么 的后缀,要么 的后缀.由两者的长度关系, 的后缀.而必要性是显然的.
考虑
某些连续以相同位置结束的子串组成的两个非空子集
(
).则要么它们
集合不相交,或者
.进一步地,这取决于
中最长串是否是
中最长串的后缀.
证明:由引理一和划分等价类,该引理是立马得到的.
考虑一个终点等价类
.等价类中所有子串长度对[x,y]构成双射,x是到
的最长路径长度.特别地长度为
中最短的,其是其他任意子串的后缀,长度为
中最长的,其他任意子串是其后缀.
证明:由后缀自动机的定义,以及引理1与集合的元素唯一性,该引理的证明是显然的.
clj大佬给出的概念:
对应
,
对应
,
则对应
确定的tree
映射state suffixlink(state t) (简写为link)
已知终止状态划分了子串集合的等价类(由性质3),并且由引理3对于状态 有一个确定的子串集合. 是其中的最长者,其余子串均是 的后缀.我们还知道 的前几个后缀(按照长度降序)在同一个终点等价类中,其余后缀(至少包括空后缀)在别的终点等价类中.令 是第一个这样的后缀的对应状态(由于后缀自动机定义这是唯一的)——对它我们建立后缀链接 .
至少包括空后缀是如何得到的?
证明:
,而
对应唯一一个后缀
.所以至少
是包括在
状态而不会在
中.
由上面所述,自然得出:
后缀链接组成了一棵以
为根的树.
证明:从最长的后缀对应的状态
开始,
构成了树的一个从叶子到根
的路径,如果非空,则继续选择其中最长的后缀对应的状态
重复,由引理3这种算法是有穷的,所以我们得到了后缀链接的为边的
结点有根树.
确定的子集偏序关系树与
中的树结点相同(同分异构体_(:3」∠)_).
证明:由
的定义,可以得出.
TODO
TODO
1.3 后缀树与后缀自动机之间的关系
TODO
2 后缀自动机算法实现
嗯…算法的自然语言描述已经在论文里讲得很清楚了,我看着一条一条理解下来没有任何问题,所以就不会赘述了,现在直接贴代码。
const int MXSIZE=100000;
struct node{int len,lnk,nx[28];}sa[MXSIZE<<1];
int sz,last;
void SAM_init()
{
memset(sa,0,sizeof(sa));
sa[sz=0].len=0;sa[0].lnk=-1;
last=sz++;
}
void SAM_extend(char c)
{
int cur=sz++,p,x=c-'a';sa[cur].len=sa[last].len+1;//新建状态
for(p=last;p+1&&!sa[p].nx[x];p=sa[p].lnk)sa[p].nx[x]=cur;//建立转移
if (p==-1)sa[cur].lnk=0;//情况1
else
{
int q=sa[p].nx[x];//获得p -c-> 状态
if(sa[q].len==sa[p].len+1)sa[cur].lnk=q;//情况2.1
else//情况2.2
{
sa[sz]=sa[q];sa[sz].len=sa[p].len+1;//新建状态
int qw=sz++;
for(;p+1&&sa[p].nx[x]==q;p=sa[p].lnk)sa[p].nx[x]=qw;//重定向
sa[q].lnk=sa[cur].lnk=qw;//重建后缀链接
}
}
last=cur;//更新last
}
3 后缀自动机的应用
字符串 中出现次数为 的子串有多少?
TODO
字符串 中字典序第x小的后缀是?
TODO
字符串 与字符串 的最长公共连续子串?
TODO
字符串集合 中所有串的最长公共前缀?
TODO
字符串 中第k小的子串是?
TODO
字符串 中是否有k长的重复子串?
TODO
字符串 中出现次数为 的子串有多少?
TODO
[1]Suffix automaton
[2]后缀自动机与线性构造后缀树
[3]后缀自动机详解
[4]后缀自动机的性质应用
[5]后缀自动机的构造
[6]后缀自动机初步
[7]【字符串新武器】后缀自动机
[8]On-Line Construction of Compact Directed Acyclic Word Graphs
[9]Combinatorial Algorithms on Words