后缀自动机(SAM)

简介

后缀——此数据结构维护一个字符串的所有后缀
自动机——一个有向无环图,可以运行,找出所有子串。
所以它是一个能处理与子串有关的强大数据结构。

如果我们用后缀建立一个Trie树,就会是这样↓(串:acadd),空间 O ( n 2 )
后缀Trie树
这种太浪费空间了,而后缀自动机,就可以重复利用节点,把空间自动机降为 O ( n )
像这样↓

构造过程

一个字符一个字符往里面添加
每次添加一个字符,会导致原串多个后缀增加,为了找到这些后缀,我们给每个节点多定义一个pre,每个节点有以下信息

  • son[26]:类似Trie,指向下一个字符节点
  • step:根节点到该节点最长路径长度,后面用于区分情况
  • pre:指向上一个要接受后一个字符的节点(每次增加字符要把pre的节点表示的后缀都要增加)

全局信息:

  • root:根
  • last:最后添加的节点

初始一个节点root

添加a
root->son[a]=1
1->pre=root;

添加c
从last一直沿着pre往上跳,如果该节点son[c]是空的,那么就连上新的节点2
1->son[c]=2;
root->son[c]=2;
2->pre=root;

添加a
从last一直往上跳,如果该节点p的son[c]有值,判断son[c]的step值是否为p的step+1,如果是,说明该节点代表的所有子串中,包含p->son[c]是最长的,son[c]代表的其它子串都是最长串的后缀,那么son[c]就可以当做最后一个节点,在以后接受新的节点在后面,那么3->pre=p->son[c];
2->son[c]=3
这里写图片描述

添加d

添加d
按照pre往上跳,如果发现p的son[c]的step不等于p的step+1,那么就必须新建节点了
新建nq(=6)复制p->son[c]的所有信息,然后使p及p的所有pre连向p->son[c]的边全部连向nq(root->son[c]=nq),nq就代替了p->son[c],而且可以接收新的字符,所以p->son[c]->pre=nq;
5->pre=nq

一些有用的性质

定义一些东西
一个子串的结束位置(endpos)为它在原串所有出现的结束位置集合,如acadd
a的结束位置为{1,3},ad的结束位置为{4}

所有在后缀自动机上走出来的路径,都是原串的子串

从根节点到某个节点的所有路径的子串,endpos集合一样,这些子串的长度为连续的一段自然数,短的为长的串的后缀:
如上图的4节点,有以下子串{“acad”,”cad”,”ad”},长度为2~4,endpos为{4};
这样,每个节点都可以表示一个endpos集合,代表的子串最长长度为step值,最短长度为pre的step+1(此性质可用于求出不同子串数量

最开始我们用pre是为了方便我们构建后缀自动机,它表示上一个能接收新字符的节点,所以pre表示的子串一定为当前节点的子串的后缀:
如4节点的pre为6,6有子串{d},是{“acad”,”cad”,”ad”}的后缀,长度为1,endpos为{4,5};每
沿着pre走一步,endpos大小就增加1,所以一个节点endpos的大小为有多少个节点pre连向它,可以利用拓扑排序求出每个节点的endpos大小(此性质可用于求出子串出现次数

(留坑:可能还有很多有用的东西)……

代码

struct Node
{
    int mx;
    Node *son[30],*pre;
}nodes[MAXL*2],*ncur=nodes+1,*root=nodes,*last=root;
void Insert(int c)
{
    Node *p=last,*np=ncur++;
    np->mx=last->mx+1;
    for(;p&&p->son[c]==NULL;p=p->pre)
        p->son[c]=np;
    if(p==NULL)
        np->pre=root;
    else
    {
        Node *q=p->son[c];
        if(q->mx==p->mx+1)
            np->pre=q;
        else
        {
            Node *nq=ncur++;
            memcpy(nq,q,sizeof(Node));
            nq->mx=p->mx+1;
            q->pre=np->pre=nq;
            for(;p&&p->son[c]==q;p=p->pre)
                p->son[c]=nq;
        }
    }
    last=np;
}

猜你喜欢

转载自blog.csdn.net/can919/article/details/79352325
今日推荐