后缀是什么
然而如果单从字符串构造来讲任何S[i…len[S]]⊂S(1⩽i⩽len[S])S[i…len[S]]⊂S(1⩽i⩽len[S])S[i\dots len[S]]\subset S(1\leqslant i\leqslant len[S])均为字符串SSS的后缀。

后缀树

§" role="presentation" style="position: relative;">§§\S1 从Trie到后缀树的变化

在WikiEn上后缀树的定义如下Suffix Tree.

In computer science, a suffix tree (also called PAT tree or, in an earlier form, position tree) is a compressed trie containing all the suffixes of the given text as their keys and positions in the text as their values.

对串SSS的所有后缀进行Trie" role="presentation" style="position: relative;">TrieTrie\text{Trie}树构造,例如”bananas”,就会得到下面的Suffix TrieSuffix Trie\text{Suffix Trie}.

对Suffix TrieSuffix Trie\text{Suffix Trie}压缩就得到了Suffix Compressed TrieSuffix Compressed Trie\text{Suffix Compressed Trie}.

这正是我们所定义的后缀树(Suffix TreeSuffix Tree\text{Suffix Tree}).
关于TrieTrie\text{Trie}树的应用,最优秀的表现就是在该树上进行的”KMP算法”,即ac自动机,一句话概括应该就是多字符串统计问题。TrieTrie\text{Trie}树的思想虽然简单却实用,有了它我们就可以设计很多关于字符串的算法。
从TrieTrie\text{Trie}到后缀树,亦是利用TrieTrie\text{Trie}对多字符串统计的性质完成对单个字符串的全面掌握——后缀树对单个字符串的所有后缀(包括该字符串本身自然是一个特殊的后缀,空字符串ϵϵ\epsilon(这里以$$\$符号表示)也是一个特殊的后缀)。后缀树自然可以对所有的后缀进行暴力建树,但这就失去了对“该TrieTrie\text{Trie}上所有字符串都是同一个字符串的后缀”的信息的利用,利用上了这个信息后缀树才从TrieTrie\text{Trie}上脱胎换骨成为一种全新的数据结构。

§§\S2 后缀树构造法

作为字符串处理中具有重要地位的数据结构——后缀树,自然不会少有人参与其中的研究。UkkonenUkkonen\text{Ukkonen}提出了完全基于内存的后缀树的线性构造,而这是我们今天讲述后缀树构造方法的主角,因为我们还是只是初涉这种数据结构而已_(:3」∠)_其他的方法可以是基于外存的,也可以是并行的,具体可以查看参考资料的第三个链接。
现在开始介绍UkkonenUkkonen\text{Ukkonen}算法。

1.Ukkonen算法的特点

(1)时间复杂度O(len[S])O(len[S])\mathrm{O}(len[S]),空间复杂度O(len[S])O(len[S])\mathrm{O}(len[S]);
(2)在线算法,分步构造,即T0=∅T0=∅T_0=\varnothing,且Ti+1=A(Ti),ATi+1=A(Ti),AT_{i+1}=A(T_i),A是算法构造,TiTiT_i是在线构造下的隐式后缀树;
(3)隐式构造,即部分后缀会因为成为某些后缀的前缀而被隐藏起来(显式构造是通过增加一个新的字典字符,使所有后缀的包含性被破坏从而每一个后缀以叶节点结尾)。

2.Ukkonen算法的核心

设已有后缀树为TiTiT_i,ββ\beta是TiTiT_i下可表示后缀.
运行法则1(隐式构造)β结束于叶子节点v:运行法则1(隐式构造)β结束于叶子节点v:\text{运行法则1(隐式构造)}\beta结束于叶子节点v:
那么更新的时候只需要把vvv的连边由(id(v),Σ)" role="presentation" style="position: relative;">(id(v),Σ)(id(v),Σ)(id(v),\Sigma)更新为(id(v),S[i+1])(id(v),S[i+1])(id(v),S[i+1])
运行法则2(分裂规则)β结束非终点路径,且β结束的位置不存在S[i+1]:运行法则2(分裂规则)β结束非终点路径,且β结束的位置不存在S[i+1]:\text{运行法则2(分裂规则)}\beta结束非终点路径,且\beta结束的位置不存在S[i+1]:
那么更新的时候新建节点v(i)v(i)v(i)作为中继,并在其下面添加v(i+1)v(i+1)v(i+1),给路径赋权S[i+1]S[i+1]S[i+1]。
运行法则3(懒惰规则)β结束非终点路径,且β结束的位置存在S[i+1]:运行法则3(懒惰规则)β结束非终点路径,且β结束的位置存在S[i+1]:\text{运行法则3(懒惰规则)}\beta结束非终点路径,且\beta结束的位置存在S[i+1]:
这时候我们什么都不做。

3.Ukkonen算法实现

我在这里并不打算做UkkonenUkkonen\text{Ukkonen}算法的解释,因为在后缀树一文中,其已经对后缀树构造做了图文并茂的阐述(虽然有人指出了这篇文章中有错误产生,推荐先看,然后倒回来看后缀树)!所以,读完他的博文以后,你可以再到回来看UkkonenUkkonen\text{Ukkonen}算法的具体实现(该算法来自于SPOJ LCS 最长公共子串 后缀自动机&后缀树(Ukkonen),我凭自己的理解做了注释(不好掌握啊…好在我们会更进一步掌握后缀数组和后缀自动机,后缀树只是辅助理解))。

struct Node
{//new_nodestatic Node buf[],*bufp;void *operator new(size_t){return bufp++;}//suffixLink:后缀链接,ch:孩子指针Node *suffixLink,*ch[28];//l:左节点,r:右节点,len:边长int l,r,len;Node(){}Node(int _l,int _r,int _len){l=_l;r=_r;len=_len;memset(ch,0,sizeof(ch));}
}
//手写new
Node::buf[N<<2],*Node::bufp=buf,
*root,
//假的root后缀链接结点,活跃结点,剩余后缀数/活跃后缀长度
*rootSuffix,*active_node;int active_length=0;
char a[N*4];
//插入S[pos]=c
void insert(int pos,char c)
{Node *curNode,*last=nullptr,*next;int x=c-'a';for(;;){while(//有子结点(curNode=active_node->ch[a[pos-active_length]-'a'])&&//active_length长于当前边active_length>=curNode->r-curNode->l){//在新结点上进行操作active_length-=curNode->r-curNode->l;active_node=curNode;}//隐式构造if(active_node==rootSuffix||(curNode&&a[curNode->l+active_length]==c)){//如果存在本次insert新构造的结点则进行后缀链接if(last)last->suffixLink=active_node;//隐式插入后缀增长了++active_length;return ;}//分裂规则,因为由前面return短路的性质,这里隐含地包含了分裂规则所满足的情况if(active_length){//分裂出子结点next=new Node(curNode->l,curNode->l+active_length,active_node->len+active_length);curNode->l+=active_length;next->ch[a[curNode->l]-'a']=curNode;active_node->ch[a[next->l]-'a']=next;//懒惰规则,由if的判断,当前是无活跃后缀的}else next=active_node;next->ch[x]=new Node(pos,INTMAX,0);//如果存在本次insert新构造的节点则进行后缀链接if(last)last->suffixLink=next;last=next;//沿着后缀链接更新active_node=active_node->suffixLink;}
}

§§\S3后缀树的应用

先暂时列举,有时候可以回来把具体实现做了。
1.S串对T的模式匹配(一次匹配所有T的个数);S串对T的模式匹配(一次匹配所有T的个数);S串对T的模式匹配(一次匹配所有T的个数);
2.求S串的最长重复子串;求S串的最长重复子串;求S串的最长重复子串;
3.两串S,T最长公共子串;两串S,T最长公共子串;两串S,T最长公共子串;
4.单串S最长回文子串。单串S最长回文子串。单串S最长回文子串。
参考:
[0]Suffix tree - Wikipedia
[1]从Trie树(字典树)谈到后缀树
[2]后缀树
[3]离散数据集的后缀树构造方法
[4]On-line construction of suffix tree,Ukkonen
[5]后缀树构造方法讲义
[6]Ukkonen后缀树算法的真·清晰解释
[7]SPOJ LCS 最长公共子串 后缀自动机&后缀树(Ukkonen)
[8](论文主要内容翻译)后缀树的构造与实现–Ukkonen Algorithm

字符串进阶——谈谈后缀全家桶(1) 后缀树相关推荐

  1. 视频教程-19年全新React教程全家桶实战redux+antd+dva+Hooks前端js视频-ReactJS

    19年全新React教程全家桶实战redux+antd+dva+Hooks前端js视频 7年的开发架构经验,曾就职于国内一线互联网公司,开发工程师,现在是某创业公司技术负责人, 擅长语言有node/j ...

  2. 【数据结构】自动机全家桶(AC、回文、后缀自动机)

    自动机全家桶 前言 一.AC自动机 1.优秀博客链接 2.问题模板 3.使用 4.本质 5.运用 6.代码模板 二.回文自动机(回文树) 1.优秀博客链接 2.问题模板 3.使用 4.本质 5.运用 ...

  3. 简(kun)单(nan)到让我开(jue)心(wang)的后缀自动机全家桶(普通后缀、广义后缀、子序列)...

    目录 参考文献 后缀自动机是什么神仙玩意? 例题 right集合.等价类以及Parent树 定义 等价类性质 Trie?DAG? 自动机?自动鸡? 自动机的基本性质 一定存在后缀自动机吗? 后缀自动机 ...

  4. 【Java进阶营】Spring全家桶系列–[SpringBoot入门到跑路]

    Spring全家桶----[SpringBoot入门到跑路] 对于之前的Spring框架的使用,各种配置文件XML.properties一旦出错之后错误难寻,这也是为什么SpringBoot被推上主流 ...

  5. AliP8大牛鼎力推荐Java岗开发进阶实战文档:Spring全家桶+Docker+Redis

    微服务最近几年在互联网行业是越来越火热,spring也是程序员不得不掌握的技术点,今天我们就来了解关于微服务中的springcloud.Docker以及spring技术源码解析.深入springboo ...

  6. 最全总结 | 聊聊 Python 数据处理全家桶(配置篇)

    聊聊 Python 数据处理全家桶(Memca 篇) 点击上方"菜鸟学Python",选择"星标"公众号 重磅干货,第一时间送达 1.前言 在实际项目中,经常会 ...

  7. 常用的 Java 工具类之 Apache 全家桶使用

    平常我们在日常的开发中会一些通用的功能封装成一些工具类,以便之后复用.但是有些常用功能,业界已经存在,我们无需造轮子,只需直接使用或借用它们的 Api ,构建我们的自己项目中工具类.这篇首先介绍平常用 ...

  8. python json key_最全总结 | 聊聊 Python 数据处理全家桶(配置篇)

    1.前言 在实际项目中,经常会接触到各种各样的配置文件,它可以增强项目的可维护性 常用配件文件的处理方式,包含:JSON.ini / config.YAML.XML 等 本篇文章,我们将聊聊 Pyth ...

  9. 我的所有优质博客全部开源啦(我自己原创的《ACM模板》《算法全家桶》《算法竞赛中的初等数论》 PDF免费下载)

    你好呀ヾ(≧▽≦*)o 我是繁凡さん 这两年来我写了很多长篇文章,主要涉及数据结构,算法,程序设计竞赛,数学,计算几何等方面的内容: <数据结构>C语言版(清华严蔚敏考研版) 全书知识梳理 ...

  10. 小邵教你玩转Typescript、ts版React全家桶脚手架

    前言:大家好,我叫邵威儒,大家都喜欢喊我小邵,学的金融专业却凭借兴趣爱好入了程序猿的坑,从大学买的第一本vb和自学vb,我就与编程结下不解之缘,随后自学易语言写游戏辅助.交易软件,至今进入了前端领域, ...

最新文章

  1. 无语!你竟然连CompletableFuture都不知道,还天天说在jdk8原地踏步~
  2. Oracle RMAN 清除归档日志
  3. Asp.net MVC调试-使用IP监听
  4. 上海社保,统筹内不能转出的疑惑
  5. 用IBM WebSphere DataStage进行数据整合: 第 1 部分
  6. Bada学习- C++以及Flash应用开发流程之创建应用工程
  7. 计算机操作员(中级工)理论知识试卷,计算机操作员中级工理论试卷.doc
  8. linux下装输入法,linux下输入法安装
  9. git学习(三)分支管理
  10. 三天学会HTML5——SVG和Canvas的使用
  11. proteus 仿真软件
  12. 面试时,当HR问“你有什么要问我的吗”时,应该问什么?
  13. Tasker Android系统增强神器,Android系统增强神器 Tasker
  14. vs项目文件夹进行分类管理
  15. mysql数据长度过长,1406 - Data too long for column ‘express_company‘ at row 1
  16. python过滤_在纯Python中映射,过滤和减少
  17. HTML figcaption 标签
  18. 隐藏文件去掉隐藏属性
  19. java绘制五子棋棋盘
  20. 程序员复工后被裁,600万房21000房贷无力偿还,给年轻人3点忠告

热门文章

  1. 【云计算】阿里云-pyodps处理指南
  2. 【Choco Disco】MMD镜头+动作打包下载.zip
  3. PySerial库的简单用法
  4. 中国高分辨率国家土壤信息格网基本属性数据集
  5. 施密特触发器HSPICE仿真【内附代码】
  6. openssl生成key和pem文件
  7. python itchat_Python itchat模块在微信上的
  8. c语言读取字符到缓冲区,C语言缓冲区问题——getchar描述
  9. Mybatis 缓存
  10. 【算法笔记】树形DP算法总结详解