后缀数组复习笔记

[后缀数组复习笔记]

首先推荐一篇写的非常好的Blog,本文中部分内容也会选自该博客。

个人认为后缀数组的核心内容其实就是对(2^x)的字符串按照(2^{x - 1})求出的第一第二关键字进行排序.然后进而一步一步对数组进行排序.

所以要用到基数排序:

基数排序在后缀数组中可以在(O(n))的时间内对一个二元组((p,q))进行排序,其中(p)是第一关键字,(q)是第二关键字

为了方便,本文用(i)代表(i)开头的后缀

首先我们要明确用到的数组的含义(非常重要!)

(sa_i):排名为(i)的后缀的位置

(rk_i):后缀(i)的排名

(x_i)后缀(i)的第一关键字

(y_i)基数排序的第二关键字,表示第二关键字为排名为(i)的后缀的位置

(c_i)(i)这个元素的出现次数,用于基数排序

(s),需要进行排序的字符串

利用倍增的思想。

AcGlVg.png

因为上来当倍增长度为(1)时,没有第二关键字

第一关键字就是其字符大小.

AcGGPs.md.png

倍增过程,(m)是其可以区分的后缀数量,(w)为当前的倍增长度.就是我上文说的(2^{x - 1})

AcGarT.md.png

这是后缀数组的核心之一.求出后缀(i)的第二关键字的大小

第一行:如果该后缀的长度不大于(2^{x - 1}),第二关键字对应的串就一定是空串.就没有排名一说了,直接顺序排下来.

第二行:如果当前为排名为(i)的后缀(此时的(sa_i)记录的长度还是(2^{x - 1 }),)他是(sa_i - w)的第二关键字,而我们是枚举的排名,所以(sa_i - w)这个后缀如果存在,他的第二关键字的排名一定是相应的排名.

基数排序不会就背吧QAQ(只需要理解第一第二关键字就好了)

AcGDIJ.png

基数排序完成后,(y)数组没用了,我们利用得到的(sa)求出新的(x_i)

但是(x_i)可能会重复,所以要利用上一轮的(x_i),这就是将(x)数组复制给(y)而不直接丢掉的原因.

如果(sa_i)(sa_{i - 1})的第一关键字排名相同且向后倍增(2^{x - 1})也相同

那么(sa_i)(sa_{i - 1})长度为(2^x)的后缀排名也是相同的.

height

上面得出的东西,都是为了(height)数组

我们引入一些概念

(lcp(x,y)):字符串(x)与字符串(y)的最长公共前缀,在这里(x)号后缀与(y)号后缀的最长公共前缀

(height[i])(lcp(sa[i],sa[i−1])),即排名为(i)的后缀与排名为(i−1)的后缀的最长公共前缀

(H[i])(height[rak[i]]),第(i)号后缀与它前一名的后缀的最长公共前缀

那么有一个结论

(H[i] >= H[i - 1] - 1)

(height[rk[i]] >= height[rk[i - 1]] - 1)

利用这个性质,我们便可以(O(n))得出(height)
AcGcxx.png

到这里后缀数组就完成了

但是关于(height)的应用是解大多数字符串题目的关键。掌握扎实

视题目而定,灵活应用

原文地址:https://www.cnblogs.com/wyxdrqc/p/10646668.html