• SAM学习笔记


    前(fei)言(hua):

    咳咳,既然是学习笔记,那肯定是边学边写的啊,所以会持续更新呀。

    SAM是啥子玩意?(在大佬讲之前完全听都没听过,但是根据PPT的排布以及讲的是字符串主题来看,这应该是“后缀自动机”了(本蒟蒻听过后缀自动机,仅仅只是听过,但是SAM这个名字就没听过了))

    然后我百度了一下SAM,搜出来这玩意......

    噫!好!我人傻了!当场爆粗口来了句氧化钙。

    然后我耐心(气急败坏)的查了查“后缀自动机”|,终于正常了。

    正题:

    后缀自动机 (suffix automaton, SAM) 是一个能解决许多字符串相关问题的有力的数据结构(”高级算法“)。

    后缀自动机中几个重要的概念:

    1.endpos(S)表示的是子串S在原串中出现的位置(末位置),例如在ababa中,endpos(ab)={2,4}(好像也有称为right集合的,不管了),这玩意是个等价集

    2.如果存在子串T以及S使得endpos(T)=endpos(S),那么我们则将S以及T归为同一类中,endpos相等的子串归在一起称为一个"状态",

    我们给各个"状态"依次编号,那么就会得到若干个状态,在这里我们约定我们记为Str(x)表示状态x的所有字符串(x是状态的编号)

    同样拿上面的例子来说事,endpos(ab)={2,4},endpos(b)={2,4},这样我们将"ab"以及"b"归为一类,称为一个"状态"

    3.后缀链接,这玩意下文详细讲

    4.parent树,这玩意下文详细讲

    后缀自动机的几个性质

    先看一组endpos的数据:

    当原串为:“abbabaa”的时候

    状态1.   空串                                      endpos={1,2,3,4,5,6,7}

    状态2.  a                                             endpos={1,4,6,7}

    状态3.  ab                                          endpos={2,5}

    状态4. b                               endpos={2,3,5}

    状态5.abb,bb                        endpos={3}

    状态6.abba,bba                  endpos={4}

    状态7.ba                                                                                 endpos={4,6}

    状态8.abbab,bbab,bab                 endpos={5}

    状态9.abbaba,bbaba,baba,aba           endpos={6}

    状态10.abbabaa,bbabaa,babaa,abaa,baa,aa          endpos={7}

    话说,泥萌有没有发现什么规律。

    对于每一个状态,里面每一个串的长度都是逐一递减的,而且后一个串就是前一个串去掉第一个字符后得到的后缀

    那么性质一来了:

    如果endpos(S)=endpos(T),那么S为T的后缀或者T为S的后缀

    不妨令|S|<|T|,那么S一定是T的后缀

    证明:如果S不是T的后缀,那么S的第1到len(S)的字符中必然有一位与对应的T的第len(T)-len(S)+1到len(T)位不同

    因为endpos(S)=endpos(T),显然与以上假设矛盾,那么不可能有S的第1到len(S)的字符中必然有一位与对应的T的第len(T)-len(S)+1到len(T)位不同

    所以如果endpos(S)=endpos(T),那么S为T的后缀或者T为S的后缀.

    性质二:

    观察得到,如果S为T的后缀,则endpos(S)包含集合endpos(T)

    如果S不是T的后缀,则endpos(S)∩endpos(T)=∅

    性质三(转移函数)**:

    挺重要的。

    对于一个状态X,我们在属于它的串后面加上一个字符ch,只要这个字符的是属于由      endpos(状态X中的字符串)后一个的字符组成的集合nxt,

    那么就满足产生的新串都属于同一个状态(这里可能我表述不大清楚,多给几个例子,方便理解)

    例如上面的例子:

    对于开篇的串的状态6,endpos()={4},那么nxt集合等于{"b"}

    那么定然abba+b,bba+b属于一个同一个状态

    对于串“abdabe”中

    某个状态为: ab,b             endpos={2,5}

    那么ab+d与b+d一定是属于同一类,

    ab+e 与 b+e一定是同一类。

    对于串"acbabacba"中

    某个状态为:acba,cba       endpos={4,9}

    那么对acba+b 与 cba+b一定是同一类的

     那么我们将会得到一个函数:f(S,c)=str(S)+(c∈nxt),S为状态号,nxt可以通过endpos求得,也就是s[endpos(str(S))+1]所得到的字符集

    这个函数将会用来进行匹配以及构建SAM!!!!

    性质四:

     前面说了“对于每一个状态,里面每一个串的长度都是逐一递减的,而且后一个串就是前一个串去掉第一个字符后得到的后缀”,那么我们观察得到每个状态都是“不完全的”

    所谓的不完全就是无法直接从状态中的最长串一直延续到空串

    例如“状态9.abbaba,bbaba,baba,aba           endpos={6}”

    如果它是完全的,那么就会有接下来的:

    “状态9.abbaba,bbaba,baba,aba,ba,a           endpos={6}”,

    显然a与ba的endpos不与前面几项endpos相同对不对?所以它们不是同一个状态

    我们要是强行将状态9完善呢?那么就会需要将“ba”以及“a”接进来,那么就需要一条链,这条链为:

    状态9----->状态7------>状态2----->状态1

    这条链肯定是唯一性的(不会有一模一样的两条链),并且被指向的那个状态所包含的字符串一定是当前状态     所有*(一定是的,因为串中字符串的长度是严格递减的)     字符串的后缀。

    同时这些链它们的终点一定会空集,也就是状态1,所以,把状态1看成根节点的话,若干条这样的链也就构成了一棵树,也就是大名鼎鼎的parent树,我们惊奇的发现我们要的后缀自动机的节点就是parent树的节点!

    bb了这么多(我太菜了,因为是边理解边写的,可能会有些误差,希望大佬们能够指出),现在终于到了讲构造后缀自动机的时候了(激动的小手准备开始打板子了)!

    还是先讲一下构造的思路(只贴代码不讲思路的博客都是耍流氓):

     后缀自动机的构造是在线的,我们通过每次插入节点的方式来实现(有之前手写二叉堆内味了)

      • last 为添加字符 c 之前,整个字符串对应的状态(一开始我们设 last=0 ,算法的最后一步更新 last )。
      • 创建一个新的状态 cur,并将 len(cur) 赋值为 len(last)+1 ,在这时 link(cur) 的值还未知。
      • 现在我们按以下流程进行(从状态 last 开始)。如果还没有到字符 c的转移,我们就添加一个到状态 cur 的转移,遍历后缀链接。如果在某个点已经存在到字符 c 的转移,我们就停下来,并将这个状态标记为p 。
      • 如果没有找到这样的状态 p ,我们就到达了虚拟状态 1 ,我们将 link(cur) 赋值为 0并退出。
      • 假设现在我们找到了一个状态 p ,其可以通过字符 c 转移。我们将转移到的状态标记为 qqq 。
      • 现在我们分类讨论两种状态,要么 len(p)+1=len(q) ,要么不是。
      • 如果 len(p)+1=len(q),我们只要将 link(cur) 赋值为 q 并退出。
      • 否则就会有些复杂。需要 复制 状态 q :我们创建一个新的状态 clone ,复制 q的除了 len 的值以外的所有信息(后缀链接和转移)。我们将len(clone) 赋值为 len(p)+1 。
        复制之后,我们将后缀链接从 cur 指向clone ,也从 q 指向 clone 。
        最终我们需要使用后缀链接从状态 p 往回走,只要存在一条通过 ppp 到状态 q 的转移,就将该转移重定向到状态 clone 。
      • 以上三种情况,在完成这个过程之后,我们将 last 的值更新为状态cur 。

    以上带点内容借鉴(抄袭)于:[ HatsuneMiku神佬的题解](https://www.luogu.com.cn/problem/solution/P3804)

    代码就先咕咕了。。。。。

    鸣谢:sh妹,Rothen,涛队,万总帮助小蒟蒻MYCui

    By MYCui
  • 相关阅读:
    spring-cloud-gateway动态路由
    spring-cloud-gateway静态路由
    activiti6官方示例笔记
    spring-cloud-gateway过滤器实践
    spring-cloud-gateway简介
    设计模式--策略模式
    学习ConcurrentHashMap1.7分段锁原理
    SpringBoot Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
    MYSQL触发器的使用
    储存过程 (创建,调用,查询,删除)
  • 原文地址:https://www.cnblogs.com/MYCui/p/13523142.html
Copyright © 2020-2023  润新知