后缀排序 后缀自动机的应用

原创 2016年08月31日 13:57:34

同步个人博客 http://sxysxy.org/blogs/23 到csdn)

给一字符串的所有后缀排个序输出,字符串长度 <= 100000

排序要求字典序小的在前面,在满足这个条件的情况下,短的后缀放到前面

例如ababa的后缀排序结果是[a, aba, ababa, ba, baba]。

暴力做法很容易想到,枚举出字符串s的总共length(s)个后缀,sort一下,然而time limit exceed (

把后缀都插入字典树? time limit exceed & memory limit exceed。

所以这个时候就需要后缀自动机登场了。

后缀排序可以看作是给字符串所有子串排序的一个特殊情况,就是子串的右端点是字符串的末尾。

对与子串的排序,我们可以构造完后缀自动机然后dfs,每次先走字典序小的字符,最后遍历完毕就是子串排序的结果。

只排序后缀呢?

今天上午英语课上我手画了一个字符串的后缀自动机然后脑补出来了一个这样的方法:

我们从后缀自动机最后一个状态St出发,向上走后缀链接树(也有叫”parent树”的),途经的状态节点可以接受的最长的字符串都是St可接受的最长的字符串的后缀。而St可接受的最长的字符串恰好就是整个字符串str(因为St是最后一个状态)。也就是说,从St出发走后缀链接一直到顶,恰好可以途径字符串str的所有后缀。

那么后缀排序就可以把从St出发走后缀链接到顶途径的所有节点都标记一下,之后像子串排序一样dfs这个后缀自动机,只在打了标记的点那里输出,就可以得到后缀排序的结果了。最后总的时间复杂度还是O(n),SAM很强啊!!!

这里写图片描述

代码

#include <cstdio>
#include <cstring>
#include <cstdarg>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN = 1e6+2;
const int SIGMA = 26;
const int BASE = (int)'a';
class SAM
{
    public:
    int last, size;
    struct state
    {
        int link, len;
        int next[SIGMA];
        bool mark;
        void init()
        {
            link = -1;
            len = 0;
            mark = false;
            memset(next, 0, sizeof(next));
        }
    }st[MAXN<<1];
    int newst()
    {
        st[size++].init();
        return size-1;
    }
    SAM()
    {
        last = size = 0;
        newst();
    }
    void expand(char newc)
    {
        int c = newc-BASE;
        int cur = newst();
        st[cur].len = st[last].len+1;
        int p;
        for(p = last; p != -1 && !st[p].next[c]; p = st[p].link)
            st[p].next[c] = cur;
        if(p == -1)
            st[cur].link = 0;
        else
        {
            int q = st[p].next[c];
            if(st[q].len == st[p].len + 1)
                st[cur].link = q;
            else
            {
                int clone = newst();
                st[clone].len = st[p].len + 1;
                st[clone].link = st[q].link;
                memcpy(st[clone].next, st[q].next, sizeof(st[q].next));
                for(; p != -1 && st[p].next[c] == q; p = st[p].link)
                    st[p].next[c] = clone;
                st[q].link = st[cur].link = clone;
            }
        }
        last = cur;
    }
    char buf[MAXN];
    int top;
    void dfs(int u)
    {
        if(top && st[u].mark)puts(buf);
        state &cur = st[u];
        for(int i = 0; i < SIGMA; i++)
        {
            if(cur.next[i])
            {
                buf[top++] = i+BASE;
                buf[top] = 0;
                dfs(cur.next[i]);
                top--;
            }
        }
    }
    void suffix_sort()
    {
        top = 0;
            //从最后一个状态开始,走后缀链接到顶,途径节点打上标记。
        for(int p = last; p; p = st[p].link)
            st[p].mark = true;
        dfs(0);
    }
}sam;

int main()
{
    char c;
    while(c = getchar())
        if(c >= 'a' && c <= 'z')break;
    sam.expand(c);
    while(c = getchar())
        if(c >= 'a' && c <= 'z')sam.expand(c);
            else break;
    sam.suffix_sort();
    return 0;
}
版权声明:本文为博主原创文章,允许转载请保留原作者信息:sxysxy

相关文章推荐

后缀自动机:O(N)的构建及应用

译者注: 原文地址http://e-maxx.ru/algo/suffix_automata 俄文用google机翻成英文再翻成中文,错误在所难免,大家多包涵……如果有什么奇怪的话直接略过吧,因为这说...

UOJ #35 后缀排序(后缀数组)

题目链接 题解:后缀数组板子 之前学后缀数组只是学了个大概,而且写的是二维的。现在从头理一遍,改成了算法导论上的写法。。 #include #include #include #include #...

后缀自动机(SAM)学习笔记

构图及原理定义算法后缀自动机(SAM)就是一个要实现能存下一个串中所有子串的算法,按一般来说应当有O(N2)O(N^2)个状态,而SAM却可以用O(N)个状态来表示所有子串,因为它把很多个本质相似的子...

SPOJ LCS2 --后缀自动机

【题目大意】     求N(N 【分析】         依旧构造第一个串的后缀自动机,用其余字符串与其匹配。         除了记录与当前字符串成功匹配的位置和位数以外,要在每个节...

后缀自动机 转变为 后缀数组

(同步个人博客 http://sxysxy.org/blogs/41 到csdn)如题 为什么会有这样的需求?像我这只会写后缀自动机的选手遇到LCP相关的问题就一脸无奈,而用后缀数组可以解决这样的问题...

后缀自动机的应用

  • 2013年03月16日 11:55
  • 41KB
  • 下载

后缀自动机的性质应用

之前自己整理过后缀自动机的构造,现在再来整理一波性质。最长公共子串这个问题非常常见,大概可以根据难易程度分成两种。两个串的最长公共子串这个问题可以用DP来解决,也可以用后缀数组。 DP的效率比较低,...

后缀自动机

  • 2013年03月16日 11:52
  • 6.56MB
  • 下载

字符匹配后缀自动机

  • 2007年10月30日 20:33
  • 450KB
  • 下载

【字符串数据结构后缀系列Part3】后缀自动机的性质和应用

学会了构建SAM之后,我们要开始学如何使用SAM来处理各种问题了. 我们先来整体看一下SAM的性质(引自2015国家集训队论文集张天扬《后缀自动机及其应用》): 1.每个状态s代表的串的长度是区...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:后缀排序 后缀自动机的应用
举报原因:
原因补充:

(最多只允许输入30个字)