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

原创 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

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

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

后缀自动机的性质应用

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

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

学会了构建SAM之后,我们要开始学如何使用SAM来处理各种问题了. 我们先来整体看一下SAM的性质(引自2015国家集训队论文集张天扬《后缀自动机及其应用》): 1.每个状态s代表的串的长度是区...
  • CreationAugust
  • CreationAugust
  • 2015年07月24日 16:51
  • 2424

[UOJ35]后缀排序

后缀自动机 后缀树 后缀数组
  • hbhcy98
  • hbhcy98
  • 2016年04月07日 19:16
  • 265

后缀自动机详解

后缀自动机 后缀自动机(单词的有向无环图)——是一种强有力的数据结构,让你能够解决许多字符串问题。 例如,使用后缀自动机可以在某一字符串中搜索另一字符串的所有出现位置,或者计算不同子串的个数——这都...
  • qq_35649707
  • qq_35649707
  • 2017年03月26日 11:34
  • 6121

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

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

【字符串新武器】后缀自动机

发链:http://neroysq.blogcn.com/articles/%E5%90%8E%E7%BC%80%E8%87%AA%E5%8A%A8%E6%9C%BA%E5%88%9D%E6%8E%A...
  • huyuncong
  • huyuncong
  • 2012年05月19日 19:33
  • 9934

后缀自动机总结……

后缀自动机(Suffix Automaton)   【有用qu的资料】 1.总之学SAM就去看clj学长的ppt就好,浅yi显lian易meng懂bi。 2.以及这个blog……模拟SAM运行的过程十...
  • Flaze_
  • Flaze_
  • 2016年08月14日 16:21
  • 1222

后缀自动机总结

后缀自动机总结 后缀自动机的构造和相关性质及复杂度证明可以看陈老师的ppt 时间复杂度据说可以用均摊分析证明是O(n)的 一开始看直接看陈老师的ppt确实有点难以理解,但是陈老师的ppt确实...
  • thy_asdf
  • thy_asdf
  • 2016年06月02日 21:53
  • 6317

hihocoder 127 后缀自动机一·基本概念

自己想了老半天,写了三百多行,没实现成功,忘记使用STL库了。。。。。。。。。。。。。。。 题目链接:http://hihocoder.com/problemset/problem/1441 ...
  • liyuanshuo_nuc
  • liyuanshuo_nuc
  • 2016年12月10日 22:04
  • 571
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:后缀排序 后缀自动机的应用
举报原因:
原因补充:

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