登封造极之字符串——后缀数组

定义:给出字符串T,将T的所有后缀(包括空串和本身)排序后,得到一个顺序,定义sa[i]数组表示第i小的后缀是从T的哪个位置开始的,如:

T=aabcd

则有sa={0,1,2,3,4,5}


构建:直接模拟,得出所有的后缀快排,则O(n^2*log n)

       效率不够,定义S[i,k]表示从第i个位置开始的长度为k的字符串,rank[i,k]表示在所有排好序的S[i,k]中的排名。

        假设长度为k的后缀数组已经构建好了,那么我们现在构建2k的后缀数组:

       1.定义compare_sa,让sa数组按此排序。

       2.根据sa数组,更新rank数组

       关键在于compare_sa,我们将S[i,2k]分解为S[i,k]和S[i+k,k],

       已知S[i,k],S[i+k,k]的排名rank[i,k],rank[i+k,k],所以我们可以通过先比较rank[i,k]与rank[j,k]的大小,再比较rank[i+k,k],rank[j+k,k]的大小,从而确定S[i,2k]与S[j,2k]的大小关系,可以迅速的排序。


参考片段: 

bool compare_sa(int i,int j){
	if (rank[i] != rank[j]) return rank[i]<rank[j];
	else{
		int ri=i+k<=n?rank[i+k]:-1;
		int rj=j+k<=n?rank[j+k]:-1;
		return ri<rj;
	}
}
void construct_sa(string S,int *sa){
	n=S.length();
	for (int i=0;i<=n;i++){
		sa[i]=i;
		rank[i]=i<n?S[i]:-1;
	}
	for (k=1;k<=n;k*=2){
		sort(sa,sa+n+1,compare_sa);
		tmp[sa[0]]=0;
		for (int i=1;i<=n;i++)
			tmp[sa[i]]=tmp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0);
		for (int i=0;i<=n;i++)rank[i]=tmp[i];
	}
}

 但仅仅有后缀数组,不足以解决所有问题,加上一个高度数组,将会更强大。

高度数组:

定义:lcp数组lcp[i]表示sa[i]与sa[i+1]所代表的后缀的最长公共前缀。


构建:设rank[i]表示位置i开始的后缀在sa中的顺序,则有rank[sa[i]]=i。

        假设我们以求出S[i...]与S[k....]的公共前缀,则如果S[i+1....],S[k+1.....]的首字母没有发生改变,则lcp[i+1]=lcp[i]-1,对于个别发生改变的只需单独检索一下即可。


参考片段:

void construct_lcp(string S,int *sa,int *lcp){
	int n=S.length();
	for (int i=0;i<=n;i++)rank[sa[i]]=i;
	int h=0;
	lcp[0]=0;
	for (int i=0;i<n;i++){
		int j=sa[rank[i]-1];
		if (h>0)h--;
		for (;j+h<n && i+h<n;h++)
			if (S[j+h] != S[i+h])break;
		lcp[rank[i]-1]=h;
	}
}


后缀数组在使用中非常灵活,如要求前缀等可以将字符串反转,求出发转后的后缀数组即为原字符串的前缀。

例:

1.最长公共子串:将S2接在S1后,则最长公共子串就在拼接后的子串的高度数组中。

2.字符串匹配:构造sa后,通过二分解决问题。(思维复杂度优于kmp,准确率高于哈希,在极端情况下效率更高)

3.最长回文:枚举中心,将原串与反转后的拼接,通过lcp求解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值