ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2022每日一题:Day 13

2022-02-18 23:34:07  阅读:208  来源: 互联网

标签:13 k2 int 后缀 2022 sa 排序 Day rk


题目:后缀排序

什么是后缀数组?他主要包含两个数组:sa和rk。
其中sa[i]表示将字符串后缀排序后第i小的编号,rk[i]表示后缀i的排名。
显然sa[rk[i]]=i,rk[sa[i]]=i。

例如字符串aba,他的后缀aba,ba,a,排序后a,aab,ab,此时
| i | 1 | 2 | 3 |
| sa | 3 | 1 | 2 |
| rk | 2 | 3 | 1 |
观察上面给出的式子,发现都成立。

那如何求后缀数组呢,最简单的方法是直接排序,不要以为时间复杂度是O(nlogn),字符串比较还有一层O(n),所以总时间复杂度是O(n^2logn)的,显然不行。

既然快排不行,那用别的排序咯,我们发现字符个数很少,因此采用基数排序,但是朴素的基数排序是O(n^2)更慢了,因此这里使用倍增优化,每次枚举范围扩大一倍,为什么可行?
试想一下,如果对于基数排序,我们也可以通过压位,以10,100,甚至更多为一个单位,显然答案不会改变,只是效率的改变罢了,因此这里同理可以得到。

具体讲一下做法,设字符串s,先求出所有s[i]的排名,这就是最基础的对应关系,也就是以一个字符为基准的方法个数,接下来就是枚举长度了,每次求出二元组(k1[i],k2[i])表示排序的两个关键字,以k2[i]为关键字排序,然后再以k1[i]为关键字排,排序号后,求出所有数的排名,如果最大的编号为字符串长度,那么就说明已经完成了后缀排序,此时sa和rk中存储的就是最开始所说的内容。
时间复杂度O(nlogn),一个比较优秀的算法。

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const int N=1e6+5;
using namespace std;
int n,cnt[N],rk[N],psa[N],sa[N],k1[N],k2[N],m;
char s[N];
int main()
{
	scanf("%s",s);
	n=strlen(s);
	m=max(n,300);
	for(int i=0;i<n;i++)
	    cnt[(int)s[i]]++;
	for(int i=1;i<m;i++)
	    cnt[i]+=cnt[i-1];
	for(int i=0;i<n;i++)
	    rk[i]=cnt[(int)s[i]]-1;
	for(int w=1;w<n;w<<=1)
	{
		for(int i=0;i<n;i++)
		{
			if(i+w>=n)
			    k2[i]=0;
			else
			    k2[i]=rk[i+w];
			k1[i]=rk[i];
		}
		for(int i=0;i<n;i++)
		    cnt[i]=0;
		for(int i=0;i<n;i++)
		    cnt[k2[i]]++;
		for(int i=1;i<m;i++)
		    cnt[i]+=cnt[i-1];
		for(int i=n-1;i>=0;i--)
		    psa[--cnt[k2[i]]]=i;
		for(int i=0;i<n;i++)
		    cnt[i]=0;
		for(int i=0;i<n;i++)
		    cnt[k1[i]]++;
		for(int i=1;i<m;i++)
		    cnt[i]+=cnt[i-1];
		for(int i=n-1;i>=0;i--)
		    sa[--cnt[k1[psa[i]]]]=psa[i];
		int tmp=1;
		rk[sa[0]]=1;
		for(int i=1;i<n;i++)
		    if(k1[sa[i]]==k1[sa[i-1]] && k2[sa[i]]==k2[sa[i-1]])
		        rk[sa[i]]=tmp;
		    else
		        rk[sa[i]]=++tmp;
		if(tmp==n)
		    break;
	}
	for(int i=0;i<n;i++)
	    printf("%d ",sa[i]+1);
	return 0;
}

标签:13,k2,int,后缀,2022,sa,排序,Day,rk
来源: https://www.cnblogs.com/honey6/p/15911607.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有