两个让我真正理解代码的资料:

2009集训队论文 网上的经典应用都是从里面抄的,还把解释给去掉了。。。真事屑

这篇博客 代码注释特别好

桶排换成快排的代码,便于理解算法思想

,这里面要减去k的原因是 sa[i] 作为 sa[i]-k 的第二关键字

循环中m=x说明所有后缀长度为x的子串已经排好,要长度为更新2m的答案

"y[i]表示第二关键字排名为i的数,第一关键字的位置"

trick:

如果s[i]太大可以先离散化一下

本质不同的子串个数 = \(\frac{n\times (n+1)}{2}\) - height数组的和

get_SA里的Y和rnk每次用完要清零 否则多组数据会出锅,字符串n+1位置记得弄成0

倒过来建SA可以实现一些例如查LCS之类的操作

把字符串拼起来建SA可以同时比较多个字符串的后缀,中间用不同的分隔符隔开(注意爆char)

struct SA {int k, sa[N], rnk[N], H[N], st[N][17];char s[N];bool cmp(int *y, int a, int b, int m) {return y[a] == y[b] && y[a + m] == y[b + m];}void Sort(int *x, int *y, int *rk) {static int C[N];for (int i = 0; i <= k; ++i) C[i] = 0;for (int i = 1; i <= n; ++i) ++C[rk[i]];for (int i = 1; i <= k; ++i) C[i] += C[i - 1];for (int i = n; i; --i) y[C[rk[x[i]]]--] = x[i];}void get_SA() {static int Y[N];int *y = Y, *rk = rnk;k = 128;for (int i = 1; i <= n; ++i) rk[i] = s[y[i] = i];Sort(y, sa, rk);for (int m = 1, p = 0; p < n; k = p, m <<= 1) {for (p = 0; p < m; ++p) y[p + 1] = n - m + p + 1;for (int i = 1; i <= n; ++i) if (sa[i] > m) y[++p] = sa[i] - m;Sort(y, sa, rk), swap(rk, y);rk[sa[p = 1]] = 1;for (int i = 2; i <= n; ++i) rk[sa[i]] = cmp(y, sa[i], sa[i - 1], m) ? p : ++p;}for (int i = 1; i <= n; ++i) rnk[sa[i]] = i, Y[i] = 0;}void get_H() {for (int i = 1, k = 0; i <= n; H[rnk[i++]] = k)for (k ? --k : 0; s[i + k] == s[sa[rnk[i] - 1] + k]; ++k);for (int i = 2; i <= n; ++i) st[i][0] = H[i];for (int j = 1; j <= __lg(n); ++j)for (int i = 2; i + (1 << j) - 1 <= n; ++i)st[i][j] = min(st[i][j - 1], st[i + (1 << j - 1)][j - 1]);}void clear() {memset(rnk, 0, sizeof rnk);}int lcp(int x, int y) {//求后缀x和y的lcpx = rnk[x], y = rnk[y];if (x > y) swap(x, y);++x;int k = __lg(y - x + 1);return min(st[x][k], st[y - (1 << k) + 1][k]);}
};

求height复杂度一句话证明:k减小O(n)次,增加O(n)次

下文引自ID为远航之曲 (blog已经挂掉了)神犇的博客

能够线性计算height[]的值的关键在于h的性质,即h[i]>=h[i-1]-1,下面具体分析一下这个不等式的由来。

我们先把要证什么放在这:对于第i个后缀,设j=sa[rank[i] – 1],也就是说j是i的按排名来的上一个字符串,按定义来i和j的最长公共前缀就是height[rank[i]],我们现在就是想知道height[rank[i]]至少是多少,而我们要证明的就是至少是height[rank[i-1]]-1。

好啦,现在开始证吧。

首先我们不妨设第i-1个字符串(这里以及后面指的“第?个字符串”不是按字典序排名来的,是按照首字符在字符串中的位置来的)按字典序排名来的前面的那个字符串是第k个字符串,注意k不一定是i-2,因为第k个字符串是按字典序排名来的i-1前面那个,并不是指在原字符串中位置在i-1前面的那个第i-2个字符串。

这时,依据height[]的定义,第k个字符串和第i-1个字符串的公共前缀自然是height[rank[i-1]],现在先讨论一下第k+1个字符串和第i个字符串的关系。

第一种情况,第k个字符串和第i-1个字符串的首字符不同,那么第k+1个字符串的排名既可能在i的前面,也可能在i的后面,但没有关系,因为height[rank[i-1]]就是0了呀,那么无论height[rank[i]]是多少都会有height[rank[i]]>=height[rank[i-1]]-1,也就是h[i]>=h[i-1]-1。

第二种情况,第k个字符串和第i-1个字符串的首字符相同,那么由于第k+1个字符串就是第k个字符串去掉首字符得到的,第i个字符串也是第i-1个字符串去掉首字符得到的,那么显然第k+1个字符串要排在第i个字符串前面,要么就产生矛盾了。同时,第k个字符串和第i-1个字符串的最长公共前缀是height[rank[i-1]],那么自然第k+1个字符串和第i个字符串的最长公共前缀就是height[rank[i-1]]-1。

到此为止,第二种情况的证明还没有完,我们可以试想一下,对于比第i个字符串的字典序排名更靠前的那些字符串,谁和第i个字符串的相似度最高(这里说的相似度是指最长公共前缀的长度)?显然是排名紧邻第i个字符串的那个字符串了呀,即sa[rank[i]-1]。也就是说sa[rank[i]]和sa[rank[i]-1]的最长公共前缀至少是height[rank[i-1]]-1,那么就有height[rank[i]]>=height[rank[i-1]]-1,也即h[i]>=h[i-1]-1。

转载于:https://www.cnblogs.com/storz/p/10593908.html

后缀数组(SA)备忘相关推荐

  1. [SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数

    problem luogu-P4070 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1,21,21,2 拼凑起来形成一个魔咒串 [1,2][1,2][1,2]. 一个魔咒串 ...

  2. 洛谷P2463 [SDOI2008]Sandy的卡片(后缀数组SA + 差分 + 二分答案)

    题目链接:https://www.luogu.org/problem/P2463 [题意] 求出N个串中都出现的相同子串的最长长度,相同子串的定义如题:所有元素加上一个数变成另一个,则这两个串相同,可 ...

  3. js数组获取index_通过事例重温一下 JS 中 常见的15 种数组操作(备忘清单),收藏...

    数组是 JS 中广泛使用的数据结构.数组对象提供了大量有用的方法,如array. forEach().array.map()等来操作数组. 在实战中,我经常对数组可能的操作和相应采用哪个更好的方法不知 ...

  4. js数组获取index_通过事例重温一下常见的 JS 中 15 种数组操作(备忘清单)

    作者:Dmitri Pavlutin 译者:前端小智 来源:dmitripavlutin.com 最近几天,公众号无套路抽奖现金 200,参与方式如下: 存而不论是一种对舆论场合的改善?(每月一次抽大 ...

  5. 通过事例重温一下常见的 JS 中 15 种数组操作(备忘清单)

    作者:Dmitri Pavlutin 译者:前端小智 来源:dmitripavlutin.com 阿里云双12已开启,新老用户均可参与,2核1G云服务器仅需79元,,更多服务器配置及价格请关注:Hi拼 ...

  6. python数组操作备忘

    一.python取数组某几行值 现有一段数组signals signals[0:2,:]取值为index=0,1两行的数据 signals[1:2,:]取值为index=1行的数据 signals[2 ...

  7. 后缀数组 + Hash + 二分 or Hash + 二分 + 双指针 求 LCP ---- 2017icpc 青岛 J Suffix (假题!!)

    题目链接 题目大意: 就是给你n个串每个串取一个后缀,要求把串拼起来要求字典序最小!! sum_length_of_n≤5e5sum\_length\_of\_n\leq 5e5sum_length_ ...

  8. 1402 后缀数组 (hash+二分)

    描述 后缀数组 (SA) 是一种重要的数据结构,通常使用倍增或者DC3算法实现,这超出了我们的讨论范围.在本题中,我们希望使用快排.Hash与二分实现一个简单的 O(n log^2⁡n ) 的后缀数组 ...

  9. 后缀数组总结(转载)

    后缀数组--处理字符串的有力工具 作者:罗穗骞 2009年1月 [摘要] 后缀数组是处理字符串的有力工具.后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现,能够实现后缀树的很多功能而时间 ...

最新文章

  1. : Andorid的Linux基础教学之五 中断机制
  2. Android 自定义debug.keystore
  3. Dos命令控制Mysql语句(自己老记不住)
  4. Maven Tomcat 部署
  5. spring-mvc教程_使用MVC模式制作游戏-教程和简介
  6. md5 算法java实现_java实现MD5算法
  7. linux查看磁盘挂载dntf,从Windows设置Linux服务器的公钥认证(ppk私钥)
  8. SAS数据挖掘实战篇【五】
  9. C++虚函数及虚函数表解析
  10. 关于重构中的“函数尽量小”的负作用
  11. Wireless Network(并查集)
  12. 计算机图形学设计线宽代码,计算机图形学画圆并改变线宽.pdf
  13. 利用 Python 进行量化投资分析 - 利率及风险资产的超额收益
  14. 乐鑫ESP32-C3开发(一)简述和目录
  15. css强制换行和强制不换行
  16. Cesium实战记录(八)三维风场+风速热力图(水平+垂直)
  17. 基于MMRotate训练自定义数据集 做旋转目标检测 2022-3-30
  18. 谷歌,高德,必应地图中英文显示
  19. 分享!快速申请抖音企业蓝V认证的方案
  20. git的使用(开发常用到的)

热门文章

  1. Publishing failed with multiple errors和Timeout waiting for Tomcat v5.5的解决方法
  2. Android线程详解
  3. Widget创建过程(将RemoteViews发给WidgetHost)
  4. 跨域资源共享的10种方式
  5. JVM学习笔记之-对象的实例化,内存布局与访问定位,直接内存(Direct Memory)
  6. 【牛客网多校】19-7-25-H题 Magic Line
  7. JavaScript-Array操作
  8. appium---【Mac】Appium-Doctor提示WARN:“ opencv4nodejs cannot be found”解决方案
  9. C++入门经典-例4.1-声明、定义和使用函数
  10. 初始化JQuery方法与(function(){})(para)匿名方法介绍