zoukankan      html  css  js  c++  java
  • 后缀自动机学习笔记

    昨天看了一下午后缀自动机,终于有了一点心得,特地来做一下笔记。

    Definitions

    首先不加证明地给出几个定义和引理:

    DFA(有限状态自动机)

    有限状态自动机的功能是识别字符串,令一个自动机A,若它能识别字符串S,就记为A(S)=True,否则A(S)=False。
    自动机由五个部分组成,alpha:字符集,state:状态集合,init:初始状态,end:结束状态集合,trans:状态转移函数。
    不妨令trans(s,ch)表示当前状态是s,在读入字符ch之后,所到达的状态。
    如果trans(s,ch)这个转移不存在,为了方便,不妨设其为null,同时null只能转移到null。
    null表示不存在的状态。
    同时令trans(s,str)表示当前状态是s,在读入字符串str之后,所到达的状态。

    后缀自动机

    就是能够识别一个串的所有后缀的自动机。后面我们可以知道,他也可以识别子串。

    right集合

    对于一个状态,我们认为这个状态代表了一个前缀长度为((len_{fa}, len_s])的所有后缀,他们的right集合都是相同的
    对于right集合,我们有两个状态的right集合要么不相交,要么一个是另一个的子集。所以我们结合这种关系,可以构造出一棵parent树,其中fa是right阶最小的包含孩子的状态。可以发现,考虑到每个状态到start的路径是连续的,所以这个parent树就是反串的后缀树
    后缀自动机的目标就是去维护所有状态的上述性质,并且考虑到状态是连续的子串,我们还需要去维护他们之间的转移。

    How to construct

    我们采用增量法来构造后缀自动机。
    假设现在的状态为p,新的状态为np,从p的所有子串映射到np的所有子串要添加的字符为c,我们显然首先要添加一条从p到np标号为c的边,然后,因为每个状态到根的路径都代表了上一个字符的后缀,所以,这条路径上的所有节点增加一个字符之后,都可以成为新串的后缀,都有可能带来right集合的改变,既然我们要维护right集合,我们就要去查看这些状态。
    考察这条路径上的节点(p_i),假设(p_i)没有一条标号为c的边,那很好,我们直接连边(p_i)到q即可。
    对于节点(p_i)已经有了一条标号为c的边,我们设原来可以转移到状态q,那么我们新增的字符c就一定会带来q的改变。
    有两种情况:

    1. 如果(len_q = len_{p_i}+1),那么q的所有子串都是由p转移过来的,那么我们直接在right集合中新增一个最后的节点就好了。
    2. 如果(len_q > len_{p_i} + 1),在这种情况下,q的子串不一定从p转移过来,我们把这些子串拆成两个集合,第一个集合为从p转移过来的,记为nq,即(len_{nq} = len_{p_i}+1),考虑到p的所有fa都是p的后缀,所以我们把所有的fa全部把连向q的边改为连向nq,根据之前的推理,q仍然有边连向。nq的除了right的所有属性与q一致。

    考虑这样做之后的par树关系,不难发现,我们应该设(fa_q = fa_{np} = q)

    Application

    下面不加证明地给出几个SAM的性质。

    1. 每个状态s代表的串的长度是区间((len_{fa_s}, len_s])
    2. 每个状态s代表的所有串在原串中的出现次数及right集合相同。
      right集合可以使用平衡树启发式合并来求。
    3. 在parent树中,每个状态的right集合是他的父状态right集合的子集。
    4. SAM的parent树是原串的反向前缀树。
      反向前缀树的定义是:把每一个前缀的反串插入到一个trie中,并且把没有分支的链合并。
      这个性质是容易发现的。考虑一个前缀在后缀自动机上的状态,我们一直沿fa指针走,每次都会变成当前串的一个后缀,直到空串,反过来看这个过程,就是在沿着反向前缀树从上往下走。
      那么,如果我们求出反串的SAM,那么他的parent树就是原串的后缀树。

    Materials

    下面列出了我在学习SAM的时候使用的一些学习资料。
    [1]陈立杰冬令营营员交流
    [2]fanhq的博客
    [3]后缀自动机及其应用——张天扬,2015国家队论文

  • 相关阅读:
    atitit查询表修改表字段没反应--解锁锁定的表
    atitit.自适应设计悬浮图片的大小and 位置
    .net 科学类型相关问题
    js eval()执行传参函数的写法
    oracle里如何将两个日期的时间差返回**时**分的格式
    .NET开源项目介绍及资源推荐:数据持久层
    highCharts 电流表、电压表
    win7 telnet命令无法使用
    ascx aspx ashx asmx 文件的作用
    Oracle 新建序列值
  • 原文地址:https://www.cnblogs.com/gengchen/p/6551978.html
Copyright © 2011-2022 走看看