后缀排序

后缀排序

即对字符串\(S\)的所有后缀根据字典序排序

实现

算法1:暴力排序

直接\(O(n)\)比较,时间复杂度\(O(n^2\log n)\)

算法2:倍增优化

我们考虑长为\(2^k\)的串的比较,该串可以分为前后均长\(2^{k-1}\)的串,那么只要知道这两个串的排名,就可以对所有\(2^k\)的串进行双关键字排序

于是每次记录\(rk[i]\)\(S[i\sim i+2^k-1]\)的排名,则\(S[i\sim i+2^{k+1}-1]\)的两个关键字为\((rk[i],rk[i+2^k])\),倍增处理\(2^k\),每次排序即可

当某后缀无法拓展至\(2^k\)时,由于越界访问\(sa[]\)\(sa[]\)值为 \(0\),则该关键字无限小,正好对应了字典序排序中“空字符字典序无限小”,因此可以不用特判,开两倍空间即可

时间复杂度\(O(n\log^2n)\)

算法3:基数排序优化

尝试优化时,我们发现双关键字排序复杂度为\(O(n\log n)\),尝试从这里着手优化

于是想到了基数排序——时间复杂度\(O(n|A|)\)\(|A|\)为数的位数,这里为\(2\),于是排序复杂度变为\(O(n)\)

时间复杂度\(O(n\log n)\)

算法4:见OIwiki

后缀数组

\(sa[i]\)记录后缀排序后排名为\(i\)的后缀的编号

在字符串领域内有相当广泛的应用

height数组

定义,\(sa\)数组中相邻两项的最长公共前缀,即\(h[i]=LCP(sa[i],sa[i-1])\)

对于\(height\)数组,有公式\(h[rk[i]]\ge h[rk[i-1]]-1\)

因此可以线性求解\(height\)数组

代码:


	for(rg int i=1,k=0;i<=n;i++) {

		if(rk[i]==1) {h[rk[i]]=0; continue;}

		if(k) --k;

		while(S[i+k]==S[sa[rk[i]-1]+k]) ++k;

		h[rk[i]]=k;

	}

\(height\)数组还有一个重要的公式:\(\displaystyle LCP(sa[i],sa[j])=\min\{h[i+1]\sim h[j]\}\)

\(height\)数组是解决一些子串问题的关键

posted @ 2024-11-11 10:53  Zhone_lb  阅读(79)  评论(0)    收藏  举报