算法详解——后缀自动机 - Canopus_wym

Canopus-wym 2021-08-09 原文


算法详解——后缀自动机


DFA


DFA,即确定性有限状态自动机,由一个五元组M=(Σ,Q,qs,F,tr)M=(\Sigma,Q,q_s,F,tr)组成,其中:

Σ\Sigma为一个有限字符集,其中每个字符cc称为一个输入符号;

QQ为一个有限状态集合;

qs∈Qq_s\in Q为初始状态;

F⊆QF\subseteq Q称为终结状态集合;

tr∈Q×Σ→Qtr\in Q\times \Sigma\to Q称为状态转换函数。

tr(q,c)=q′tr(q,c)=q'表示当前状态为qq,输入符号为cc时,自动机MM将自动转换成下一个状态q′q',此时称q′q'qq的一个后继状态。


以上全是废话。

大家应该都知道AC自动机吧,如果不知道可以去看这一篇博客:http://blog.csdn.net/wang3312362136/article/details/78659403

一个DFA,就是一个有向图,有一个起点,有一些标有字符的边,有一个或多个终点,从这个起点,按照一个字符串上的字符,按顺序走与字符串的字符相同的边,最终走到了终点,就说明这个DFA能够识别这个字符;如果走到了非法状态qϕq_\phi,或者走到了一个不是终点的状态,那么说明这个DFA不能识别这个字符串。

对于一个状态ppqq,如果任何一个能够从pp转换到终点的字符串都可以从qq转换到终点,反之也成立,那么就说明ppqq是等价状态,记为KaTeX parse error: Unexpected character: \’\’ at position 2: p̲~q

如果一个DFA中没有等价状态,那么这个自动机叫做最小状态自动机。

SAM

即后缀自动机,是能识别一个串所有后缀的最小状态自动机。

SAM的性质

它有哪些性质呢?


Theorem 1
对于任意一个T∈Σ∗T\in \Sigma^*tr(qs,T)̸=qϕtr(q_s,T)\not=q_\phi当且仅当TTSS的一个字串。
Lemma 2
T∈Σ∗T\in \Sigma^*是一个非空字符串,right(T)right(T)表示TTSS中所有结束位置的集合,则有L(tr(qs,T))={sufr+1∣r∈right(T)}L(tr(q_s,T))=\{suf_{r+1}\mid r\in right(T)\}
Theorem 3
T1T_1T2T_2SS的两个非空字符串,则tr(qs,T1)=tr(qs,T2)tr(q_s,T_1)=tr(q_s,T_2)的充要条件是right(T1)=right(T2)right(T_1)=right(T_2)
Theorem 3.5
记一个状态qqrightright集合为RqR_q,则rightright集合恰好为RqR_q的串,其长度一定在一个区间内,称之为qq的合法长度区间,记为[minlq,maxlq][minl_q,maxl_q],对应从初始状态到这个状态的最短长度和最长长度。
Lemma 4
任取两个不同的状态p,qp,q,则下列三式中必有一式成立:
(1)Rp⋂Rq=ϕR_p\bigcap R_q=\phi (2)Rp⊆RqR_p\subseteq R_q (3)Rq⊆RpR_q\subseteq R_p
Lemma 5
若一个状态pp是状态ppparentparent状态,当且仅当RqR_q是最小真包含RpR_p的集合,那么q∈Q {qϕ}q\in Q\text{\ }\{q_\phi\}parentparent状态存在且唯一。
Theorem 6
q∈Q {qϕ}q\in Q\text{\ }\{q_\phi\}ppqqparentparent状态,则有maxlp=minlq−1maxl_p=minl_q-1,此时pp对应的所有字串都是qq的后缀。
所以,我们在后缀自动机中只需要存储每个节点parentparent状态,和maxlmaxl值即可。
Theorem 7
对串SS构建后缀自动机MM,则有MM的状态数∣Q∣≤2∣S∣+1|Q|\leq 2|S|+1
Theorem 8
对串SS构建后缀自动机MM,则合法状态转换边的数量不超过3∣S∣3|S|


  1. 后缀自动机中只需存储SS的字串对应的状态;
  2. 一个状态对应的字串,它们的rightright集合相等,且长度取值必定对应一个区间;
  3. 每个状态与parentparent状态的关系必定构成一棵parentparent树;
  4. 一个状态的最小合法长度恰好比parentparent状态的最大合法长度多11
  5. 后缀自动机是一个线性结构。

证明?

由自己的感觉可得

自己参阅资料吧。(其实可以背结论的)

SAM的构建

增量法,每次在后缀自动机中添加一个字符,然后对当前的SAM进行更新。


显然,添加一个字符并不会造成状态的合并,但有可能造成状态的分离,而分离的状态只有可能是在添加前后缀状态和非后缀状态都可以转换到它,此时,这个状态需要分裂成只能被后缀状态转换的状态和只能被非后缀状态转换的状态。(这个情况之后再讲)

设添加前这个串是SS,添加的字符为cc,设tr(qs,S)=ptr(q_s,S)=p,由于所有后缀节点在parentparent树上都是祖先关系,因此把它们记为v1=p,v2,v3,⋯ ,vk=qsv_1=p,v_2,v_3,\cdots ,v_k=q_s

由于tr(qs,Sc)=qϕtr(q_s,Sc)=q_\phi,那么我们需要新建一个节点np=tr(qs,Sc)np=tr(q_s,Sc)(这个是显然的)
那么maxlnp=∣S∣+1maxl_{np}=|S|+1Rnp′={n+1}R'_{np}=\{n+1\}

对于一个后缀状态vv,如果tr(v,c)=qϕtr(v,c)=q_\phi(即vv没有符号为cc的合法转换边),那么将tr(v,c)=nptr(v,c)=np即可,正确性显然。

vpv_pv1,v2,v3,⋯ ,vkv_1,v_2,v_3,\cdots,v_k中第一个存在符号为cc的合法转换边的状态,那么记qqtr(vp,c)tr(v_p,c),取r=Rqr=R_q中的最小值,此时记Q1=S[r,r],Q2=S[r−1,r],⋯ ,Qr=S[1,r]Q_1=S[r,r],Q_2=S[r-1,r],\cdots,Q_r=S[1,r],下标就是串的长度。

由于S[r]S[r]显然为cc,那么记Q1=P0c,Q2=P1c,⋯ ,Qr=Pr−1cQ_1=P_0c,Q_2=P_1c,\cdots,Q_r=P_{r-1}c,显然,Pi=S[r−i,r−1]P_i=S[r-i,r-1]。那么状态qq对应的串就是Qminlq,⋯ ,QmaxlqQ_{minl_q},\cdots,Q_{maxl_q}所有能转换到qq的状态pp对应的串就是SQ={Pminlq−1,⋯ ,Pmaxlq−1}S_Q=\{P_{minl_{q}-1},\cdots,P_{maxl_q-1}\}

又由于vpv_p对应的后缀串只有SP={P0,⋯ ,Pmaxlvp}S_P=\{P_{0},\cdots,P_{maxl_{v_p}}\}

讨论qq的状态:

  1. maxlvp=maxlq−1maxl_{v_p}=maxl_q-1时,显然有SQ⊆SPS_Q\subseteq S_P,那么,所有能通过输入符号cc转换到qq的状态都是后缀状态,此时qq不会发生状态的分裂。而对于vpv_pparentparent树上的祖先,显然tr(vp,c)tr(v_p,c)更不可能发生分裂。
  2. maxlvp<maxlq−1maxl_{v_p}<maxl_q-1时,qq的合法长度区间可以分成两个部分:[minlq,maxlvp+1][minl_q,maxl_{v_p}+1]以及[maxlvp+2,maxlq][maxl_{v_p}+2,maxl_q]。前者只有后缀状态能转移到它,后者只有非后缀状态能转移到它。
    那么新建一个状态nqnq,对应前者,新图中的q′q'对应后者。由于RnqR_{nq}显然只比RqR_{q}多一个∣S∣+1|S|+1,而∣S∣+1|S|+1之后并没有字符,没有状态能通过这个转移,那么nqnq的状态转换边与qq完全相同。
    而对于vpv_pparentparent树上的祖先,显然,如果tr(vp,c)=qtr(v_p,c)=q则指向nqnq,否则不变。
    对于npnpparentparent:当v[1,n]v_{[1,n]}都不存在cc的转换边,说明npnp是第一次出现,parentparentqsq_s。否则,npnpparentparentqq或者nqnq,取决于是否建立了nqnq这个状态。
    对于q′q'nqnqparentparent:如果没有发生分裂,则不改变。如果发生了分裂,设原图中qqparentparentparqpar_q,则parqpar_qqqnqnq这三个状态在parentparent树上构成祖孙关系,进一步推理得parnq=parq,parq′=nqpar_nq=par_q,par_{q'}=nq

代码

struct samnode
{
  samnode* tr[26];
  samnode* par;
  int maxl;

  int init(int l=0)
  {
    memset(tr,0,sizeof tr);
    par=NULL;
    maxl=l;
    return 0;
  }
};

struct suffix_automaton
{
  samnode* qs;
  samnode* qlast;
  samnode node[maxn*3];
  int cntnode;

  inline int clear()
  {
    delete qs;
    delete qlast;
    qs=new samnode;
    qlast=new samnode;
    qs->init();
    qlast=qs;
    cntnode=0;
    return 0;
  }

  inline int addchr(int ch)
  {
    samnode* p=qlast;
    samnode* np=&node[++cntnode];
    np->init(p->maxl+1);
    qlast=np;
    while((p!=NULL)&&(p->tr[ch]==NULL))
      {
        p->tr[ch]=np;
        p=p->par;
      }
    if(p==NULL)
      {
        np->par=qs;
        return 0;
      }
    samnode* q=p->tr[ch];
    if(p->maxl+1!=q->maxl)
      {
        samnode* nq=&node[++cntnode];
        nq->init(p->maxl+1);
        memcpy(nq->tr,q->tr,sizeof q->tr);
        nq->par=q->par;
        q->par=nq;
        np->par=nq;
        while((p!=NULL)&&(p->tr[ch]==q))
          {
            p->tr[ch]=nq;
            p=p->par;
          }
      }
    else
      {
        np->par=q;
      }
    return 0;
  }
};
发表于
2018-02-22 17:39 
Canopus_wym 
阅读(167
评论(0
编辑 
收藏 
举报

 

版权声明:本文为Canopus-wym原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Canopus-wym/p/10376228.html

算法详解——后缀自动机 - Canopus_wym的更多相关文章

  1. Java三年经验 – 面试总结

    一轮面试下来,由最初的自信什么都能做,到现在感觉什么都不会做;但是面对面试官,却更坦然。 对自己还能记得起来的 […]...

  2. B – 来找一找吧 HihoCoder – 1701(排列组合 + 同余差值相同)

    这次到渣渣问桶桶了。。。 准备给你n个数a1, a2, … an,桶桶你能从中找出m个特别的整数吗 […]...

  3. 漫画 | 数据库设计全过程 – Java知音号

    漫画 | 数据库设计全过程 数据库设计知多少? 引言 数据库已成为现代信息系统的基础和核心,它的设计全过程可划 […]...

  4. oracle 数据库备份与恢复 – zhangfd

    oracle 数据库备份与恢复 oracle 数据库备份与恢复 包含四个部分: 1、数据泵备份与恢复 2、rm […]...

  5. 禁止chrome浏览器自动升级的方法 – sammyzhang

    禁止chrome浏览器自动升级的方法 最近用selenium+chrome做测试或爬虫的时,发现chrome被 […]...

  6. The Tongsha ferry (通沙汽渡) over Changjiang river – WebQ

    The Tongsha ferry (通沙汽渡) over Changjiang river When I g […]...

  7. 蔡琴 -《蔡琴2004 银色月光下演唱会》(Under The Moon Light)AC3 5.1CH – 电脑人生

    蔡琴 -《蔡琴2004 银色月光下演唱会》(Under The Moon Light)AC3 5.1CH 20 […]...

  8. js控制只能输入数字 – nickTimer

    js控制只能输入数字 onkeyup=clearNoNum(this) function clearNoNum […]...

随机推荐

  1. 点评国内各大在线app生成平台

    第一个:应用之星–无需编码的在线手机应用开发平台–移动开发平台-Androi应用开发 […]...

  2. 二十、mysql数据库

    二十、mysql数据库 一、mysql数据库的基础知识 一、什么是数据   描述事物的符号记录称为数据,描述事 […]...

  3. 实战经验|如何处理后台产品的业务需求

    最近在设计ERP系统,对内部使用的产品需求深有感悟,B端产品相较于C端来说,需求更为清晰,但是不谨慎处理,仍然 […]...

  4. 缺陷管理规范–bug管理流程

    缺陷管理流程图     缺陷管理流程图是为了有效的跟踪,管理bug的处理情况,指导测试团队和开发人员有效的处理 […]...

  5. 从 hadoop 1.0 到 hadoop 2.0 的演化

    1. 概述 在 Google 三篇大数据论文发表之后,Cloudera 公司在这几篇论文的基础上,开发出了现在 […]...

  6. 字体图标制作的方法 – ranyonsue

    字体图标制作的方法 web端和移动端为什么需要做字体图标? 性能好是最主要的原因,可以减少http请求。在之前 […]...

  7. 滑动窗口算法基本原理与实践

    学过计算机网络的同学,都知道滑动窗口协议(Sliding Window Protocol),该协议是 TCP协 […]...

  8. JQuery制作网页——表单验证

    1、  表单验证:减轻服务器的压力、保证输入的数据符合要求; 2、  常用的表单验证:日期格式、表单元素是否为 […]...

展开目录

目录导航