后缀数组就是将字符串所有后缀排序后的数组,设字符串为S,令后缀Suffix(i)表示S[i..len(S)]。用两个数组记录所有后缀的排序结果:

  • Rank[i]记录Suffix(i)排序后的序号,即Suffix[i]在所有后缀中是第Rank[i]小的后缀
  • SA[i]记录第i位后缀的首字母位置,即Suffix[SA[i]]在所有后缀中是第i小的后缀

然后就是怎么快速求所有后缀的顺序了,其中的关键是如何减少两个后缀比较的复杂度
方法是倍增法,定义一个字符串的k-前缀为该字符串的前k个字符组成的串,关于在k-后缀上的定义Suffix(k,i)、SA[k,i]和Rank[k,i]类似于前,则有

  • 若Rank[k,i]=Rank[k,j]且Rank[k,i+k]=Rank[k,j+k],则Suffix[2k,i]=Suffix[2k,j]
  • 若Rank[k,i]=Rank[k,j]且Rank[k,i+k]<Rank[k,j+k],则Suffix[2k,i]<Suffix[2k,j]
  • 若Rank[k,i]<Rank[k,j],则Suffix[2k,i]<Suffix[2k,j]

这样就能在常数时间内比较Suffix(2^k, i)之间的大小,从而对Suffix(2^k,i)时行排序,最后当2^k>n时,Suffix(2^k, i)之间的大小即为所有后缀之间的大小

于是求出了所有后缀的排序,有什么用呢?主要是用于求它们之间的最长公共前缀(Longest Common Prefix,LCP)

令LCP(i,j)为第i小的后缀和第j小的后缀(也就是Suffix(SA[i])和Suffix(SA[j]))的最长公共前缀的长度,则有如下两个性质:

  1. 对任意i<=k<=j,有LCP(i,j) = min(LCP(i,k),LCP(k,j))
  2. LCP(i,j)=min(i<k<=j)(LCP(k-1,k))

第一个性质是显然的,它的意义在于可以用来证明第二个性质。第二个性质的意义在于提供了一个将LCP问题转换为RMQ问题的方法:
令height[i]=LCP(i-1,i),即height[i]代表第i小的后缀与第i-1小的后缀的LCP,则求LCP(i,j)就等于求height[i+1]~height[j]之间的RMQ,套用RMQ算法就可以了,复杂度是预处理O(nlogn),查询O(1)

然后height的求法要用到另一个数组:令h[i]=height[Rank[i]],即h[i]表示Suffix(i)的height值(同时height[i]就表示Suffix(SA[i])的height值),则有height[i]=h[SA[i]]
然后h[i]有个性质:

  • h[i] >= h[i-1]-1

用这个性质我们在计算h[i]的时候进行后缀比较时只需从第h[i-1]位起比较,从而总的比较的复杂度是O(n),也就是说h数组在O(n)的时间内解决了。求出了h数组,根据关系式height[i]=h[SA[i]]可以在O(n)时间内求出height数组,于是可以在O(n)时间内求出height数组,从而整个LCP问题就解决了^_^

然后后缀数组的应用就是利用它的LCP在需要字符串比较时降低复杂度。同时由于后缀数组的有序性可以很方便地使用二分

于是总结一下要点:

  • 利用倍增算法在O(nlogn)的时间内对后缀数组进行排序
  • 利用h数组的性质在O(n)的时间内求出储存排序后相邻后缀间的LCP数的组height
  • 利用LCP的性质将平凡LCP问题转化为height数组上的RMQ问题

本题是求两字符串的最长公告子串(注意是子串不是子序列),构造出SA,RA和HEIGHT后,答案就是最大的HEIGHT,但这个最大的HEIGHT可能是同一个串中的,

所以这个最大的HEIGHT同时要满足sa[i-1]和sa[i]不在同一个串中。

转载于:https://www.cnblogs.com/ACAC/archive/2010/05/24/1743092.html

转一个后缀数组的简单总结:相关推荐

  1. 【2012百度之星/资格赛】H:用户请求中的品牌 [后缀数组]

    时间限制: 1000ms 内存限制: 65536kB 描述 馅饼同学是一个在百度工作,做用户请求(query)分析的同学,他在用户请求中经常会遇到一些很奇葩的词汇.在比方说"johnsonj ...

  2. 看动画学算法系列之:后缀数组suffix array

    文章目录 简介 后缀数组的定义 后缀数组的创建流程 在后缀数组中查找某个字符串 创建LCP 后缀数组和后缀树的比较 简介 在之前的文章中,我们讲到了后缀树和它的一些特性.后缀树主要用来做模式匹配中,比 ...

  3. 后缀数组 TYVJ P1860 后缀数组

    /*P1860 后缀数组 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 我们定义一个字符串的后缀suffix(i)表示从s[i]到s[length(s)]这 ...

  4. 笨办法学 Python · 续 练习 22:后缀数组

    练习 22:后缀数组 原文:Exercise 22: Suffix Arrays 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 我想告诉你一个关于后缀数组的故事.在一段时间里, ...

  5. 后缀数组(学习心得)

    后缀数组 后缀数组是一种处理字符串的利器,很多字符串的问题都可以通过后缀数组来实现. 后缀数组说简单一点就是对一个字符串的所有后缀子串进行排序. 我来举个例子,比如字符串banana 刚开始的时候它的 ...

  6. NOI数据结构:后缀数组

    后缀数组的简单介绍 https://www.bilibili.com/video/BV1Ct41147xB 0229省选课[后缀数组] https://www.bilibili.com/video/B ...

  7. bzoj 2754 [SCOI2012]喵星球上的点名 后缀数组+莫队

    先把所有串按顺序放到一起,两个串间加非法字符隔开,求一个后缀数组. 然后对于询问,满足条件的子串在后缀数组上一定是连续一段区间. 这个区间的左右端点可以在读入的过程中二分求. 然后这个问题变成了多组询 ...

  8. [bzoj4566][HAOI2016]找相同字符(后缀数组)

    题目 传送门 题解 这里:把两个串用一个很大的字符连接起来,求一个后缀数组. 考虑怎样暴力的算答案. 在 rank  r a n k rank数组中从前往后枚举起点,对于每个枚举的起点,都暴力的往后扫 ...

  9. 寻找一个字符串的重复子串 后缀数组

    什么是后缀数组 令字符串 S=S[1]S[2]...S[n]S=S[1]S[2]...S[n]{\displaystyle S=S[1]S[2]...S[n]} , S[i,j]S[i,j]{\dis ...

最新文章

  1. Scala 求三个数中的最大数代码示例
  2. 文档扫描:深度神经网络在移动端的实践
  3. 源代码安装g95编译器
  4. 哈苏相机加持!一加9 Pro海外抢先发布:采用120Hz LTPO屏幕
  5. QT每日一练day28:QT中的2D绘图知识概念——讲义截图
  6. Python3用requests,multiprocessing多线程爬取今日头条图片
  7. mysql碎片处理_mysql优化数据库和mysql数据库碎片处理
  8. iOS 本地自动打包工具
  9. uploadify php 重命名,自定义uploadify服务器端上传脚本
  10. 习题8.16 (简单方法)输入一个字符串,内有数字和非数字字符
  11. 计算机怎么安错误,电脑安装软件时提示安装过程出错系统设置未被修改怎么办...
  12. 智能制造数据分析综合应用方案
  13. XML学习记录(归纳总结,方便查看)
  14. 渐变按钮 css,CSS3 Gradient Buttons
  15. 苹果手机充电口接触不良怎么办_苹果连充电口都要干掉?
  16. 服务器win10系统开机慢,Win10系统更新后开机变得很慢的解决方法
  17. 激活函数(sigmoid、Tanh、ReLU、Leaky ReLU、ELU、Maxout)
  18. Professional SharePoint 2007 Web Content Management Development: Building Publishing Sites with Offi
  19. 成都月嫂提醒你,宝宝的疫苗接种时间
  20. Js中var,let,const的区别

热门文章

  1. 4.17杭州KubeMeet 开发者沙龙·云原生应用管理专场来啦!
  2. Flink Forward Asia 2020 - Keynote 总结
  3. 计算机视觉如何给企业带来不同?
  4. 支付宝研究员王益的建议:“学好语文,才能写好代码”
  5. Arduino UNO WIFI开发板,学习必备开发套件
  6. The world at your fingertips — 天涯明月刀幕后(后记)
  7. ASP.NET Core微服务(六)——【redis操作】
  8. ORACLE11G自动维护任务简析
  9. shell脚本--sed的用法
  10. 微信小程序家庭记账本开发进度二