算法详解——后缀自动机 - 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. 用友U6操作经验之一 — 转自www.sapjob.cn – kitty – Qin

    用友U6操作经验之一 — 转自www.sapjob.cn           单据号:录入或自动生 […]...

  2. 手机如何修改host文件 – 贝利

    手机如何修改host文件 常常在想本地开发的时候使用pc端测试移动端,由于有安全域名限制,因此在本地修改了机器 […]...

  3. 计算机名称和IP地址 – 努力成长静待花开

      获取本地IP地址      得到远程机IP地址与描述      若仅仅是查看IP地址     ...

  4. hbase常用命令总结 – 在路上——

    hbase常用命令总结 创建表:表名:csliyb:testuser列族:name 例子:create \&# […]...

  5. [转]分流分压总电阻计算公式 – casio1374633

    [转]分流分压总电阻计算公式 link:http://blog.sina.com.cn/s/blog_6757 […]...

  6. 微信小程序设置全局字体 – 猫头唔食鱼

    微信小程序设置全局css,需要在app.wxss文件中设置page的样式 page { font-family […]...

  7. Linux 纯字符界面的玩法 – 京山游侠

    关于 Linux 字符界面的一些玩法。 Linux 纯字符界面的用途## 装逼必备 省资源,服务器一般不安装图 […]...

  8. java函数式编程之Consumer – lijingran

    java函数式编程之Consumer 参考https://blog.csdn.net/z345434645/a […]...

随机推荐

  1. 页游变速齿轮作弊的前端处理(转)

    变速齿轮这样的作弊软件已经不是什么新鲜的玩意了,但是它们的出现缺验证的破坏掉游戏的运营与维护。下面来说说怎么在 […]...

  2. 你不可不知的自定义注解

    作者 | cherry-peng 来源 | https://blog.csdn.net/xsp_happybo […]...

  3. cisco(思科)交换机配置篇【两】

    上一页大家津津乐道cisco基本操作命令开关,而端午假期,该cisco简单的开关配置,并希望请您分享“端午节快 […]...

  4. 使用Spring安全表达式控制系统功能访问权限

    一、SPEL表达式权限控制 从spring security 3.0开始已经可以使用spring Expres […]...

  5. 人工智能AI佛祖-HOTOKE AI

    HOTOKE AI,人工智能AI佛祖,自然语言生成模型制作的聊天机器人。这个佛祖可以跟你自然对话,回答你的问题,提供信息和建议,让你有种和虚拟佛祖交流的感觉,寻求生活中的指导和安慰,感兴趣的朋友可以体验一下。...

  6. 基于opencv的车牌提取项目

    初学图像处理,做了一个车牌提取项目,本博客仅仅是为了记录一下学习过程,该项目只具备初级功能,还有待改善 第一部 […]...

  7. 快速排序详解包含图片演示步骤

    最近从网上看了很多快排的博客,发现有的不是那么容易理解,有的存在些许的错误. 无奈自己研究了下快排,现在做一下 […]...

  8. webpack打包工具的初级使用方法

      这里下载的是webpack的3.8.1版本(新版更新的使用有些问题)   什么是webpack? 他是一个 […]...

展开目录

目录导航