后缀家族已知成员

        后缀树
        后缀数组
        后缀自动机
        后缀仙人掌
        后缀预言
        后缀Splay ?
后缀树是后缀数组和后缀自动机的祖先? 功能还是比较强大的,在回文串或者字典序方面还是有用处。 而且现在已经有了线性的建树方法。
(但其实我也没用过后缀树。)下面对比后缀自动机和后缀数组
 
 
  • 单个字符串问题                                                                  不等号是“优于”,&&是差不多(以下是个人感觉)

    • 1重复子串

      • 1,1 可交叉最长重复子串                              后缀自动机>=后缀数组                          都是基本题,但是前者代码稍短
      • 1,2 不可交叉最长重复子串                          后缀数组>=后缀自动机                          前者易于判断交叉;后者则需要记录每个状态所有出现的位置
      • 1,3 可交叉的k次最长重复子串                     后缀自动机>=后缀数组                          后者需+二分判定;前者无需判断,直接拓扑出每个状态的次数
    • 2子串个数问题
      • 2,1 不相同子串个数                                     后缀自动机&&后缀数组                          都是基本功能,易于实现。
    • 3循环子串问题
      • 3,1 求最小循环节                                         后缀数组,kmp                                           后缀自动机应该不行。
      • 3,2 重复次数最多的连续重复子串                后缀数组
  • 两个字符串串问题

    • 1公共子串问题

      • 1,1 最长公共子串                                         后缀自动机&&后缀数组                          都是基本功能
    • 2子串个数问题
      • 2,1 特定长度的公共子串                              后缀自动机&&后缀数组                           二者的基本功能
  • 多个字符串问题

    • 1公共子串问题

      • 1,1 在k个字符串中的出现的最长子串           广义后缀自动机>=后缀数组(KMP也可以求多个串的最长公共字串)               (具体效率谁高取决于数据)
      • 1,2 在每个字符串中出现k次的最长子串       广义后缀自动机>=后缀数组
      • 1,3 在每个字符串中或反转后出现的最长子串 广义后缀自动机?后缀数组
  • 其他

  • 最小表示法: 后缀自动机
  • 最小循环节 :后缀数组

个人感觉:

单串和两串的题,基本上用后缀数组或者后缀自动机都可以实现。多串的题用广义后缀自动机也是非常强的,有点题如果要用后缀数组,则必须要用RMQ(树状数组||ST)+二分,甚至要用Splay来解决。当然灵活的运用后缀数组加各种工具来解决问题,才能应对各种难题,毕竟后缀自动机也是有局限的。个人更倾向于写后缀自动机,感觉好实现一点,代码也好看一点。

下面对比一下多串字符串的处理

广义后缀自动机的题:

POJ3294:  题意:给定一些模板字符串,求一个最长公共字串,这个最长公共字串至少在一半以上的字符串里出现过。

  对比:如果是后缀数组,则要+二分+RMQ;而广义后缀自动机只需要记录出现的位置,最后传递即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<memory>
#include<cmath>
#define maxn 350003
using namespace std;
int n,len,ans,Max,now;
char s[],cap[];
struct SAM
{
int ch[maxn][],fa[maxn],maxlen[maxn],Last,sz;
int root,nxt[maxn],size[maxn];
void init()
{
sz=;
root=++sz;
memset(size,,sizeof(size));
memset(ch[],,sizeof(ch[]));
memset(nxt,,sizeof(nxt));
}
void add(int x)
{
int np=++sz,p=Last;Last=np;
memset(ch[np],,sizeof(ch[np]));
maxlen[np]=maxlen[p]+;
while(p&&!ch[p][x]) ch[p][x]=np,p=fa[p];
if(!p) fa[np]=;
else {
int q=ch[p][x];
if(maxlen[p]+==maxlen[q]) fa[np]=q;
else {
int nq=++sz;
memcpy(ch[nq],ch[q],sizeof(ch[q]));size[nq]=size[q]; nxt[nq]=nxt[q];
maxlen[nq]=maxlen[p]+;
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
while(p&&ch[p][x]==q) ch[p][x]=nq,p=fa[p];
}
}
for(;np;np=fa[np])
if(nxt[np]!=now) {
size[np]++;
nxt[np]=now;
}else break;
}
void dfs(int x,int d){//输出
if(d!=maxlen[x] || d>ans) return;
if(maxlen[x]==ans && size[x]>n){ puts(cap); return; }
for(int i=;i<;++i)
if(ch[x][i]){ cap[d]=i+'a'; dfs(ch[x][i],d+); cap[d]=; }
}
};
SAM Sam;
int main()
{
while(~scanf("%d",&n)&&n){
Sam.init();
for(int i=;i<=n;i++) {
scanf("%s",s+);
Sam.Last=Sam.root;
len=strlen(s+);
now=i;
for(int j=;j<=len;j++) Sam.add(s[j]-'a');
}
Max=;ans=;n>>=;
for(int i=;i<=Sam.sz;i++)
if(Sam.size[i]>n&&Sam.maxlen[i]>ans) { Max=i;ans=Sam.maxlen[i];}
if(ans) Sam.dfs(,);
else puts("?");
puts("");
}
return ;
}

SPOJ8093  题意:给定一些模板串,询问每个匹配串在多少个模板串里出现过。

对比:同上。传递的两种方式:每加一个字符传递一次;也可以用bitset记录在哪里出现过等到加完所有字符串后再拓扑排序,然后“亦或”向上传递。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 200003
using namespace std;
int ch[N][],fa[N],l[N],n,m,len;
int r[N],v[N],cnt,np,p,nq,q,last,root,nxt[N],now,size[N];
char s[N];
void extend(int x)
{
int c=s[x]-'a';
p=last; np=++cnt; last=np;
l[np]=l[p]+;
for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if (!p) fa[np]=root;
else {
q=ch[p][c];
if (l[q]==l[p]+) fa[np]=q;
else {
nq=++cnt; l[nq]=l[p]+;
memcpy(ch[nq],ch[q],sizeof ch[nq]); size[nq]=size[q]; nxt[nq]=nxt[q];
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
for (;np;np=fa[np])
if (nxt[np]!=now) {
size[np]++;
nxt[np]=now;
}
else break;
}
int main()
{
scanf("%d%d",&n,&m);
root=++cnt;
for(int i=;i<=n;i++) {
scanf("%s",s+);
last=root;
len=strlen(s+);
now=i;
for (int j=;j<=len;j++)
extend(j);
}
for (int i=;i<=m;i++) {
scanf("%s",s+);
len=strlen(s+);
p=root;
for (int j=;j<=len;j++) p=ch[p][s[j]-'a'];
printf("%d\n",size[p]);
}
}

(对于后缀数组,在下还不是很敏感,多做点之后再补充一些上来)

顺便发两张后缀自动机的图

状态 子串 endpos
S 空串 {0,1,2,3,4,5,6}
1 a {1,2,5}
2 aa {2}
3 aab {3}
4 aabb,abb,bb {4}
5 b {3,4,6}
6 aabba,abba,bba,ba {5}
7 aabbab,abbab,bbab,bab {6}
8 ab {3,6}
9 aabbabd,abbabd,bbabd,babd,abd,bd,d {7}

【整理】如何选取后缀数组&&后缀自动机的更多相关文章

  1. 字符串的模板 Manacher kmp ac自动机 后缀数组 后缀自动机

    为何scanf("%s", str)不需要&运算 经常忘掉的字符串知识点,最好不加&,不加&最标准,指针如果像scanf里一样加&是错的,大概是未定 ...

  2. loj6173 Samjia和矩阵(后缀数组/后缀自动机)

    题目: https://loj.ac/problem/6173 分析: 考虑枚举宽度w,然后把宽度压位集中,将它们哈希 (这是w=2的时候) 然后可以写一下string=“ac#bc” 然后就是求这个 ...

  3. bzoj 3172 后缀数组|AC自动机

    后缀数组或者AC自动机都可以,模板题. /************************************************************** Problem: 3172 Us ...

  4. [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)

    https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...

  5. SPOJ694 DISUBSTR --- 后缀数组 / 后缀自动机

    SPOJ694 DISUBSTR 题目描述: Given a string, we need to find the total number of its distinct substrings. ...

  6. POJ2774Long Long Message (后缀数组&后缀自动机)

    问题: The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to ...

  7. POJ1743 Musical Theme (后缀数组 & 后缀自动机)最大不重叠相似子串

    A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the ...

  8. SPOJ- Distinct Substrings(后缀数组&后缀自动机)

    Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...

  9. BZOJ 2946 [Poi2000]公共串 (二分+Hash/二分+后缀数组/后缀自动机)

    求多串的最长公共字串. 法1: 二分长度+hash 传送门 法2: 二分+后缀数组 传送门 法3: 后缀自动机 拿第一个串建自动机,然后用其他串在上面匹配.每次求出SAM上每个节点的最长匹配长度后,再 ...

随机推荐

  1. Lumen开发:lumen源码解读之初始化(4)——服务提供(ServiceProviders)与路由(Routes)

    版权声明:本文为博主原创文章,未经博主允许不得转载. 前面讲了singleton和Middleware,现在来继续讲ServiceProviders和Routes,还是看起始文件bootstrap/a ...

  2. Mockito when(...).thenReturn(...)和doReturn(...).when(...)的区别

    在Mockito中打桩(即stub)有两种方法when(...).thenReturn(...)和doReturn(...).when(...).这两个方法在大部分情况下都是可以相互替换的,但是在使用 ...

  3. echart 图表自定义样式

    initChart: function (id) { this.charts = echarts.init(document.getElementById(id)) this.charts.setOp ...

  4. 九度OJ 1350:二叉树的深度 (二叉树)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1044 解决:614 题目描述: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长 ...

  5. 【python】-- 队列(Queue)、生产者消费者模型

    队列(Queue) 在多个线程之间安全的交换数据信息,队列在多线程编程中特别有用 队列的好处: 提高双方的效率,你只需要把数据放到队列中,中间去干别的事情. 完成了程序的解耦性,两者关系依赖性没有不大 ...

  6. CMDB的四种模式

    为什么要有CMDB? CMDB --Configuration Management Database 配置管理数据库. 1.为了实现资产的自动采集,资产的自动更新, 为了搭建公司自动化平台的基础则需 ...

  7. IE下获取不到Response添加的cookie的解决方法

    原博客地址: http://blog.csdn.net/wjdd1/article/details/16341189 在百度上查询了好久也没有查询到结果,于是自己用ie的开发者工具进行跟踪,JSESS ...

  8. Java之线程池(二)

    关于线程和线程池的学习,我们可以从以下几个方面入手: 第一,什么是线程,线程和进程的区别是什么 第二,线程中的基本概念,线程的生命周期 第三,单线程和多线程 第四,线程池的原理解析 第五,常见的几种线 ...

  9. JVM调优-工具篇

    原文地址 16年的时候花了一些时间整理了一些关于jvm的介绍文章,到现在回顾起来还是一些还没有补充全面,其中就包括如何利用工具来监控调优前后的性能变化.工具做为图形化界面来展示更能直观的发现问题,另一 ...

  10. shell一些方法

    字符串截取转自原文地址:http://www.jb51.net/article/56563.htm 一:字符串截取 有var变量: var=http://www.aaa.com/123.htm 1. ...