初学后缀自动机

参考链接:http://blog.sina.com.cn/s/blog_7812e98601012cim.html

后缀自动机和后缀数组一样,刚开始学的时候十分不好懂,学完之后觉得自己很厉害了,然后拿到题目就傻眼了

对于字符串这里的很多算法的性质都一样,如果不能完全理解其构造的意义,那么是根本做不了题目的,例如KMP

算法,开始学习的时候next函数是用来匹配用的,后来发现基本上考KMP的题目根本不会涉及到匹配,每次都是

根据next值来判断串具有的性质,所以对next值不理解就无法做题,同样后缀数组,没有题目会叫你输出sa数组

或者rank数组的值的,都会让你根据这两个数组的值,来构造一个其他的什么东西,然后解题,比如说height数组

这里也一样,构造一个后缀自动机也不能说明你对这个算法很熟悉,只能说明,你知道有这么个算法!



表示目前对后缀自动机理解有限


后缀自动机的阐述以及构造方法上面的连接已经说明的很清楚了,感谢那位博主的分享

下面我阐述一下我学习过程中对遇到问题的理解:

1、为什么当len=len+1的时候直接就处理,不是的时候要copy出来

如果是的话,那么说明这个节点只能有上面一个节点过来,在后缀自动机中一个儿子可以有多个父亲

len表示的从根节点到这个位置的最长路径,如果目前这个父亲个他的儿子相差一个,表示这个儿子

只能由这一个父亲过来,否则就不是,不是的话如果直接处理就会出现问题了

至于为什么要copy出来,这个其实也不太好理解,copy出来,重新设置len值,然后把后面指向原来的

全部、指向这个刚copy出来的节点,这样目的是

1、copy出来,防止直接处理漏掉很多后缀

2、沿路将指向copy前的那个节点的可加后缀的节点全部转移到新的节点,目的是防止出现重复后缀情况


说的很乱,因为还不是很理解

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define maxn 10000
char str[maxn];
struct node
{
    node *next[26];
    node *f;
    int len;
    node():len(0),f(0)
    {
        memset(next,0,sizeof(next));
    }
}re_root,*tail=&re_root;
int build_suffix_array(char ch)
{
    int temp=int(ch-'a');
    node *p=new node(),*q=tail,*r;
    p->len=tail->len+1;
    for( ;q&&!q->next[temp];q=q->f) q->next[temp]=p;
    tail=p;
    if(q==NULL) tail->f=&re_root;
    else
    if(q->next[temp]->len==q->len+1) tail->f=q;
    else
    {
        r=new node();
        *r=*(q->next[temp]);
        r->len=q->len+1;
        tail->f=r;
        p=q->next[temp];
        p->f=r;
        for( ;q&&q->next[temp]==p;q=q->f) q->next[temp]=r;
    }
return 0;
}
int pos;
int triverse(node *root)
{
    bool flag=true;
    for(int i=0;i<26;i++)
    {
        if(root->next[i])
        {
            str[pos++]='a'+i;
            triverse(root->next[i]);
            pos--;
            flag=false;
        }
    }
    if(flag)
    {
        str[pos]=0;
        printf("%s\n",str);
    }
    return 0;
}
int main()
{
        int i,k,t;
        scanf("%s",str);
        for(i=0;str[i];i++)
        build_suffix_array(str[i]);
        printf("Ok\n");
        pos=0;
        triverse(&re_root);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值