后缀数组学习笔记--height数组

显然单一个后缀数组是没有什么软用的,加上height才有用。。

height[i]表示sa[i]和sa[i-1]的最长公共前缀,这东西求起来快同时好用,主要有三条性质:

定义LCP(i,j)=lcp(Suffix(SA[i]),Suffix(SA[j])。

1.对任意1<=i<j<k<=n,LCP(I,k)=min{LCP(I,j),LCP(j,k)}

2.设i<j,LCP(i,j)=min{LCP(k-1,k)|i+1<=k<=j}  (是由1的推论)

求出1.2两性质可得,计算LCP(I,j)等同于询问一维数组height中下标在i+1到j范围内的所有元素的最小值。如果height数组是固定的,这就是求区间最小,随便st表搞一下就可以。(1.2两性质主要决定它的用处)

3.设h[i]=height[Rank[i]](其实h[i]就是说下标为i的位置的height),那么对于i>1且Rank[i]>1,一定有h[i]>=h[i-1]-1。(这一性质决定了h数组能在O(n)的时间内快速求出,而h数组和height关系就如同sa和rnk,也是互逆的)

具体求法:

若Rank[i]=1,则h[i]=0。字符比较次数为0.

 若i=1或者h[i-1]<=1,则直接将Suffix(i)和Suffix(Rank[i]-1)从第一个字符开始依次比较直到有字符不同,由此算出h[i]。

 否则,说明i>1,Rank[i]>1,h[i-1]>1,根据性质3,Suffix(i)和Suffix(Rank[i]-1)至少有前h[i-1]-1个字符是相同的,于是字符比较可以从h[i-1]开始,直到某个字符不相同,由此计算出h[i]。

参考资料:https://www.cnblogs.com/ECJTUACM-873284962/p/6618870.html

代码:(短的飞起)

void cal_h()
{
	int nw,j;
	for(int i=1;i<=n;i++)
	{
		if(rnk[i]==1)ht[rnk[i]]=0;//显然height[1]=0,因为没有rnk[0]... 
		if(nw)--nw;//h[i]>=h[i-1]-1;
		j=sa[rnk[i]-1];
		while(s[i+nw]==s[j+nw]&&i+nw<=n&&j+nw<=n)++nw;
		ht[rnk[i]]=nw;
	}
}

猜你喜欢

转载自blog.csdn.net/caoyang1123/article/details/81258588