`
yzmduncan
  • 浏览: 330321 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

数据结构之——后缀数组

阅读更多

    后缀数组,很精妙的数据结构。

    后缀:从母串的某一位置开始到结尾,suffix(i) = Ai,Ai+1...An。

    后缀数组:后缀数组SA是个一维数组,它保存1...n的某个排列SA[1],SA[2]...SA[n],并且保证suffix(SA[i])<suffix(SA[i+1]),也就是将S的n个后缀从小到大排好序后的开头位置保存到SA中。

    名次数组:名次数组Rank[i]保存的是以i开头的后缀的排名,与SA互为逆。简单的说,后缀数组是“排在第几的是谁”,名次数组是“你排第几”。

    为了方便比较,通常在串的末尾添加一个字符,它是从未出现并且最小的字符。

 

    求解后缀数组的算法主要有两种:倍增算法DC3算法。在这里使用的是许智磊的倍增算法,复杂度为nlogn。

    关于详细求解后缀数组的算法,详见许智磊2004国家集训队论文。

 

后缀数组的应用:

    最长公共前缀:先定义height数组,height[i] = suffix(SA[i-1])和suffix(SA[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。


 

例1:最长公共前缀

    给定一个串,求任意两个后缀的最长公共前缀。

解:先根据rank确定这两个后缀的排名i和j(i<j),在height数组i+1和j之间寻找最小值。(可以用rmq优化)

 

例2:最长重复子串(不重叠)(poj1743)

解:二分长度,根据长度len分组,若某组里SA的最大值与最小值的差>=len,则说明存在长度为len的不重叠的重复子串。

 

例3:最长重复子串(可重叠)

解:height数组里的最大值。这个问题等价于求两个后缀之间的最长公共前缀。

 

例4:至少重复k次的最长子串(可重叠)(poj3261)

解:二分长度,根据长度len分组,若某组里的个数>=k,则说明存在长度为len的至少重复k次子串。

 

例5:最长回文子串(ural1297)

    给定一个串,对于它的某个子串,正过来写和反过来写一样,称为回文子串。

解:枚举每一位,计算以这个位为中心的的最长回文子串(注意串长要分奇数和偶数考虑)。将整个字符串反转写在原字符串后面,中间用$分隔。这样把问题转化为求某两个后缀的最长公共前缀。

 

例6:最长公共子串(poj2774)

    给定两个字符串s1和s2,求出s1和s2的最长公共子串。

解:将s2连接到s1后,中间用$分隔开。这样就转化为求两个后缀的最长公共前缀,注意不是height里的最大值,是要满足sa[i-1]和sa[i]不能同时属于s1或者s2。

 

例7:长度不小于k的公共子串的个数(poj3415)

    给定两个字符串s1和s2,求出s1和s2的长度不小于k的公共子串的个数(可以相同)。

解:将两个字符串连接,中间用$分隔开。扫描一遍,每遇到一个s2的后缀就统计与前面的s1的后缀能产生多少个长度不小于k的公共子串,这里s1的后缀需要用单调栈来维护。然后对s1也这样做一次。

 

例8:至少出现在k个串中的最长子串(poj3294)

    给定n个字符串,求至少出现在n个串中k个的最长子串。

将n个字符串连接起来,中间用$分隔开。二分长度,根据长度len分组,判断每组的后缀是否出现在不小于k个原串中。

 

求解后缀数组的模板:

const int N = 20005;//串A的最大长度
const int MAX = 1000100;//串A的最大值
//int n,m,k;
int SA[N], rank[N], height[N], key[N];
int A[N], C[MAX], t1[N+1], t2[N+1];

//倍增法求sa[]-----待排序的字符串放在r 数组中,r[]为整型数组, 从r[0]到r[n-1],长度为n,且最大值小于m
//约定除r[n-1]外所有的r[i]都大于0, r[n-1]=0
//结果放在sa 数组中,从sa[0]到sa[n-1]
//先对所有后缀的第一个字符进行排序(采用挖坑式的基数排序,即统计每个字符的个数,以便在扫描时总能将字符放入合适的位置),放入sa中
void da(int n, int m)
{
	int i, j, l, s,*t;
	int *X = t1, *Y = t2;
    memset(C, 0, sizeof(C));
	for (i=0;i<n;i++) C[X[i] = A[i]]++;
	for (i=1;i<m;i++) C[i] += C[i-1];
	for (i=n-1;i>=0;i--) SA[--C[X[i]]] = i;
	for (l=1; l<n; l<<=1)
	{
		for (i=n-l,j=0;i<n;i++) Y[j++] = i;
		for (i=0;i<n;i++) if (SA[i] >= l) Y[j++] = SA[i] - l;
		for (i=0;i<n;i++) key[i] = X[Y[i]];
		memset(C, 0, sizeof(C));
		for (i=0;i<n;i++) C[key[i]]++;
		for (i=1;i<m;i++) C[i] += C[i-1];
		for (i=n-1;i>=0;i--) SA[--C[key[i]]] = Y[i];
		t = X;
		X = Y;
		Y = t;
		X[SA[0]] = j = 0;
		for (i=1;i<n;i++)
		{
			if (Y[SA[i]] != Y[SA[i-1]] || Y[SA[i]+l] != Y[SA[i-1]+l])
				j++;
			X[SA[i]] = j;
		}
		m = j + 1;
		if (m==n) break;
	}
 
	for (i=0;i<n;i++)
		rank[SA[i]] = i;
    return;
}

//height[i]:suffix(sa[i-1])与suffix(sa[i])的最长公共前缀,即排名相邻的两个后缀的最长公共前缀
void calheight(int n)
{
	int i,j,k=0;
	for(i=0; i<n; i++)
	{
		if (k > 0)
            --k;
		if(rank[i] == 0)
			height[0] = 0;
		else
		{
			j = SA[rank[i] - 1];
			while(A[i+k] == A[j+k])
				k++;
			height[rank[i]] = k;
		}
	}
}
//串A[0]...A[n-1]
da(n,1000001);	//m的最大值不超过1,000,000
calheight(n);

 

 

  • 大小: 44.6 KB
分享到:
评论

相关推荐

    11.罗穗骞《后缀数组——处理字符串的有力工具》.zip

    罗穗骞的《后缀数组——处理字符串的有力工具》详细介绍了这一数据结构及其应用,包含算法源码和解题源码,对于学习者来说是一份宝贵的资源。 首先,后缀数组是一个有序的字符串集合,由输入字符串的所有后缀组成。...

    后缀数组——罗穗骞附件(源码)

    后缀数组与最长公共前后缀(Longest Common Prefix, LCP)数组相结合,可以形成更强大的工具——后缀数组+LCP结构。LCP数组记录了后缀数组相邻元素之间的最长公共前缀长度,它能进一步提升某些问题的解决效率。 在...

    后缀数组——处理字符串的有力工具1

    后缀数组是一种在字符串处理中非常重要的数据结构,它被广泛应用于信息学竞赛和算法设计中。后缀数组可以看作是一系列字符串后缀的排序,其中每个元素都是原字符串的一个后缀,按字典序排列。相比于后缀树,后缀数组...

    后缀数组——罗穗骞ppt版

    后缀数组的实现和应用 后缀数组是处理字符串的有力工具之一,它可以高效地解决许多字符...后缀数组是一个非常有用的数据结构,它可以高效地解决许多字符串问题。DC3 算法是一个优秀的算法,可以高效地计算出后缀数组。

    后缀数组——处理字符串的有力工具.pdf

    后缀数组是一种高效处理字符串的数据结构,在信息学竞赛和许多字符串处理的实际应用中占据着重要地位。它不仅与后缀树具有相似的功能,而且在编程实现上更加简洁,占用内存也更少,成为后缀树的一个实用替代品。 一...

    后缀数组资料打包(论文+PPT+笔记)

    后缀数组是计算机科学中一种重要的数据结构,主要用于处理字符串问题。它在字符串搜索、模式匹配、DNA序列分析等领域有着广泛的应用。后缀数组的概念首次由Manber和Myers在1993年提出,其核心思想是将一个字符串的...

    后缀数组——处理字符串的有力工具_罗穗骞.ppt

    后缀数组是一种强大的数据结构,尤其在处理字符串问题时,能提供高效且灵活的解决方案。它的核心思想是对一个给定字符串的所有后缀进行排序,并存储这些排序后的后缀的起始位置,形成所谓的后缀数组(Suffix Array, ...

    后缀数组((处理字符串的有力工具))

    后缀数组是计算机科学中处理字符串的一种重要数据结构,它在文本索引、字符串搜索、生物信息学等领域有着广泛的应用。后缀数组的概念源于1990年代,由Udi Manber首次提出,其核心思想是将一个字符串的所有后缀按照...

    后缀数组(Suffix Array)

    后缀数组是一种数据结构,用于存储字符串所有可能的后缀的排序列表。这种数组在文本处理、字符串匹配、生物信息学等领域有着广泛的应用。通过构建后缀数组,可以有效地解决一系列问题,如查找字符串中的重复子串、...

    后缀数组的一些资料

    文件"后缀数组——处理字符串的有力工具.pdf"和"后缀数组.pdf"可能提供了后缀数组的基础理论和实例解析,帮助读者深入理解这一数据结构。"后缀数组——处理字符串的有力工具.ppt"可能是教学演示文稿,通过幻灯片形式...

    后缀数组C++实现代码

    后缀数组是一种数据结构,它存储了字符串所有后缀按字典序排序后的索引值。具体来说,对于一个长度为 n 的字符串 S,其后缀数组 SA 是一个长度为 n 的数组,其中 SA[i] 表示字典序第 i 小的后缀在原字符串中的起始...

    罗穗骞《后缀数组——处理字符串的有力工具》(有算法源码和解题源码)

    罗穗骞的《后缀数组——处理字符串的有力工具》一书,结合IOI2009论文和源码,为学习者提供了深入理解后缀数组及其应用的宝贵资源。 首先,我们来了解一下后缀数组的基本概念。对于一个字符串S,其所有后缀按字典序...

    许智磊关于后缀数组的PDF文件

    后缀数组作为一种高效的数据结构,在字符串处理领域具有重要作用。相较于后缀树,后缀数组不仅实现起来更加简便,而且在时间和空间复杂度方面表现优异,使其成为信息学竞赛及实际应用中的首选工具。本文将详细介绍...

    09-罗穗骞-后缀数组——处理字符串的有力工具1

    后缀数组是处理字符串问题的一种高效数据结构,它在信息学竞赛和算法设计中具有重要地位。相较于后缀树,后缀数组更易于编程实现,同时在时间和空间效率上都有不错的表现。本文由罗穗骞撰写,详细探讨了后缀数组的...

    poj3261.zip_POJ 3261

    POJ 3261是一道经典的在线编程竞赛题目,它涉及到一个重要的数据结构——后缀数组,对理解后缀数组的概念及其应用有着极大的帮助。本文将深入探讨后缀数组的基本原理、构建方法以及如何利用其解决实际问题。 后缀...

    后缀数字资料

    后缀数组与LCP阵列结合可以形成更强大的数据结构——suffix tree(后缀树),虽然后缀树在某些查询上比后缀数组更快,但构建过程较复杂。后缀数组和LCP阵列的组合在某些情况下能提供与后缀树相当的功能,且构建时间...

Global site tag (gtag.js) - Google Analytics