【文文殿下】后缀自动机(Suffix Automaton,SAM)学习笔记
前言
后缀自动机是一个强大的数据结构,能够解决很多字符串相关的(String-related)问题。
例如:他可以查询一个字符串在另一个字符串中出现的所有子串,以及查询一个字符串中本质不同的字符串的个数。
后缀自动机可以理解为一个字符串的所有子串的压缩图,对于一个长度为\(n\)的字符串,它只需要\(O(n)\)的空间,以及\(O(n)\)的时间进行在线搭建(如果我们把字符集视作常数)。如果我们把字符集视作变量\(k\),那么他的空间复杂度和时间复杂度都可以做到\(O(nlogk)\)。后缀自动机是在1983年被提出的,随后于1985年人们发现了一个线性构造的方法。
后缀自动机的定义
对于一个给定的字符串\(S\),它的后缀自动机是一个能够接受它的所有后缀的最简确定性有限状态自动机(Minimal Deterministic Finite Automaton,MDFA)。
后缀自动机的性质(形态)
后缀自动机是一张有向无环图(Oriented Acyclic Graph,OAG),每个节点被称作状态(State),每条边称作两个状态之间的转移(Transition)。
有一个状态被称作起始状态(Initial State,IS)。它是整张OAG的起点(不存在一个状态,可以转移到它,即入度为0)。
每一个转移都表示一个字符,而一条从起始状态到其他状态的路径,都表示一个字符串。
每一个状态都认为是终态(Terminal State,TS)。如果我们能从起始状态转移到终态,那么我们经过的路径所代表的字符串一定是原串的某个后缀(我们认为空串是任何串的后缀)。
后缀自动机是满足以上性质的自动机中,拥有最少状态的一个自动机。
子串性质
后缀自动机最简单和最重要的一个性质是:它包含了一个字符串中所有子串的信息。后缀自动机上的所有路径(不必从起始状态出发),组成了原串中所有的子串。
每一个状态代表了所有从起始状态到它的路径所代表的字符串的集合。
一些简单的SAM的例子
空串

字符串 "a"

字符串"aa"

字符串"ab"

字符串"aba"

字符串"abb"

字符串"abbb"

Right集合
一个状态所代表的所有的字符串的右端点的位置。根据性质,显然这个状态里面的所有字符串的出现位置的右端点都重合。
所代表的串的长度
一个状态下所代表的所有的字符串的长度,一定是一段连续的区间。
后缀链接(parent)
两个状态\(u,v\),如果\(u\)中所有字符串都是\(v\)中某个字符串的后缀,那么从\(v\)向\(u\)连一条名为后缀链接的虚拟边,这条边并不存在于MDFA中。每个节点有且仅有一条后缀链接连向其他的状态,但他可能被多个后缀链接所指向。
我们把满足上述条件的\(u,v\),称作\(u\)是\(v\)的父亲(Parent)。
显然,一个状态所代表的字符串中最短的那条,是它父亲状态所代表的最长的那条字符串的长度+1
字符串"abcbc"的SAM与后缀链接的展示

线性构造算法(参见Menci)





代码实现
void extend(int x) { // 构建
int np = ++cnt,p=last;
Right[np]=1;
mx[np]=mx[p]+1;
last=np;
while(p&&!tr[p][x]) tr[p][x]=np,p=par[p];
if(!p) par[np]=1;
else {
int q = tr[p][x];
if(mx[q]==mx[p]+1) {
par[np]=q;
}
else {
int nq = ++cnt;
mx[nq]=mx[p]+1;
memcpy(tr[nq],tr[q],sizeof tr[q]);
par[nq]=par[q];par[q]=par[np]=nq;
while(p&&tr[p][x]==q) tr[p][x]=nq,p=par[p];
}
}
return;
}
void topsort() {//求Right数组大小
for(int i = 1;i<=cnt;++i) ++c[mx[i]];
for(int i = 1;i<=n;++i) c[i]+=c[i-1];
for(int i = 1;i<=cnt;++i) id[c[mx[i]]--]=i;
for(int i = cnt;i;--i) Right[par[id[i]]]+=Right[id[i]];
return;
}
【文文殿下】后缀自动机(Suffix Automaton,SAM)学习笔记的更多相关文章
- SAM学习笔记
SAM学习笔记 后缀自动机(模板)NSUBSTR(Caioj1471 || SPOJ 8222) [题意] 给出一个字符串S(S<=250000),令F(x)表示S的所有长度为x的子串中,出现次 ...
- 后缀自动机SAM学习笔记
前言(2019.1.6) 已经是二周目了呢... 之前还是有一些东西没有理解到位 重新写一下吧 后缀自动机的一些基本概念 参考资料和例子 from hihocoder DZYO神仙翻译的神仙论文 简而 ...
- 后缀自动机(SAM) 学习笔记
最近学了SAM已经SAM的比较简单的应用,SAM确实不好理解呀,记录一下. 这里提一下后缀自动机比较重要的性质: 1,SAM的点数和边数都是O(n)级别的,但是空间开两倍. 2,SAM每个结点代表一个 ...
- 2018.07.17 后缀自动机模板(SAM)
洛谷传送门 这是一道后缀自动机的模板题,这道题让我切身体会到了后缀自动机的方便与好写. 代码如下: #include<bits/stdc++.h> #define N 2000005 #d ...
- SAM学习笔记&AC自动机复习
形势所迫,一个对字符串深恶痛绝的鸽子又来更新了. SAM 后缀自动机就是一个对于字符串所有后缀所建立起的自动机.一些优良的性质可以使其完成很多字符串的问题. 其核心主要在于每个节点的状态和$endpo ...
- 回文自动机(PAM) 学习笔记
原文链接www.cnblogs.com/zhouzhendong/p/PAM.html 前置知识 无. (强行说和KMP有关也是可以的……) 关于回文串的一些性质 1. 一个长度为 n 的字符串最多有 ...
- 后缀自动机----一种将字符串变成DAG的方法
后缀自动机 (suffix automaton, SAM) 是一个能解决许多字符串相关问题的有力的数据结构.(否则我们也不会用它) 举几个例子,以下的字符串问题都可以在线性时间内通过 SAM 解决 1 ...
- 后缀自动机(SAM)
*在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符 ...
- 后缀自动机(SAM)奶妈式教程
后缀自动机(SAM) 为了方便,我们做出如下约定: "后缀自动机" (Suffix Automaton) 在后文中简称为 SAM . 记 \(|S|\) 为字符串 \(S\) 的长 ...
随机推荐
- VUE项目 - IE报vuex requires a Promise polyfill in this browser问题解决
第一步: 安装 babel-polyfill . babel-polyfill可以模拟ES6使用的环境,可以使用ES6的所有新方法 npm install --save babel-polyfill ...
- VMware 克隆网卡无法启动
问题描述: 最近学习 hadoop,环境准备搭建在虚拟机之上,装好一台虚拟机克隆完成后,网卡无法启动. 多年前,初学 Linux 的时候,就遇到过这个问题,记录的笔记找不到了,简单记录一下. shel ...
- App登录状态维持
转载地址:http://www.jianshu.com/p/4b6b04244773 目前APP大都支持长登录,就是用户登录一次后,如果用户没有主动注销.清除APP缓存数据或卸载APP,就在一段时间内 ...
- 【332】Machine Learning
Reference: 决策树方法-对买电脑进行分类预测 Reference: 最邻近规则分类(K-Nearest Neighbor)KNN算法应用 Reference: python 内建函数 str ...
- jquery怎么根据后台传过来的值动态设置下拉框、单选框选中
$(function(){ var sex=$("#sex").val(); var marriageStatus=$("#marriageStatus").v ...
- PHP 微信公众号开发 - 获取用户信息
项目微信公众号开发,记录获取用户微信号信息,和用户openid 1,登录微信公众平台 点击登录微信公众平台 2,获取公众号开发信息 登陆之后在 开发->基本配置 3,设置IP白名单 在这里添加服 ...
- 借用服务器百度BAE
3一.简介 对于普通的开发者,不必要买服务器和买域名,这时要将自己的项目传到服务器上,就用到了百度BAE这样的,可以直接传项目的服务器. 二.申请 登录百度开放平台上 三.登录网址,选择要使用的项目 ...
- 企业搜索引擎开发之连接器connector(二十)
连接器里面衔接数据源与数据推送对象的是QueryTraverser类对象,该类实现了Traverser接口 /** * Interface presented by a Traverser. Used ...
- ASP.NET Core2使用Autofac实现IOC依赖注入竟然能如此的优雅简便
初识ASP.NET Core的小伙伴一定会发现,其几乎所有的项目依赖都是通过依赖注入方式进行链式串通的.这是因为其使用了依赖注入 (DI) 的软件设计模式,代码的设计是遵循着“高内聚.低耦合”的原则, ...
- JAVA下查看进程中线程占用CPU较高的代码
执行以下代码获得进程的线程.并找到CPU占用较高的线程ID ps -mp 16935 -o THREAD,tid,time 执行以下代码,通过线程ID获得16进制的线程标识 printf &quo ...