初學後綴數組

後綴數組就是把一個字符串的後綴排序,然後就可以再亂搞一些東東。

DC3看着就累,還是倍增好。

當初看代碼覺得雖然不長但是理解起來並不容易,各種數組有各自的意義很容易搞混。

特別是要理解基數排序。每次按第二關鍵字排序再按第一關鍵字排序,可以保證在第一關鍵字相同時第二關鍵字的大小關係也正確。

白書上的數組有s(字符串)、sa、x、y、c,計算height還用到了rank。

我的代碼是照着白書上的寫的(發現白書上的代碼有幾個小的細節問題)。

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=1e6+10;
char s[maxn];

int n,m,p;
int sa[maxn],x[maxn],y[maxn],c[maxn];
//sa當前排好的後綴 x每個後綴的rank y由第二關鍵字排好的後綴 c記錄每種相同的個數及前綴和 
int height[maxn];

int main() {
	gets(s); n=strlen(s); m='z'+1;
	for(int i=0;i<n;++i) c[x[i]=s[i]]++;
	for(int i=1;i<m;++i) c[i]+=c[i-1];
	for(int i=n-1;i>=0;--i) sa[--c[x[i]]]=i;//sa[c[w]-1]爲放入目前rank爲w的可放的最後一個位置 
	for(int k=1;k<=n;k<<=1) {
		p=0;
		for(int i=n-1;i>=n-k;--i) y[p++]=i;//把已經沒有第二關鍵字的放在前 
		for(int i=0;i<n;++i) if(sa[i]>=k) y[p++]=sa[i]-k;//根據第二關鍵字放入對應的第一關鍵字位置(後綴的起始位置) 
		for(int i=0;i<m;++i) c[i]=0;
		for(int i=0;i<n;++i) c[x[i]]++;
		for(int i=1;i<m;++i) c[i]+=c[i-1];//記錄每個後綴第一關鍵字的信息 
		for(int i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];//根據第一關鍵字排序 
		
		swap(x,y);//此時y已經無用,我們需要更新x數組必須用到曾經的x數組(判斷相同的情況) 
		p=1; x[sa[0]]=0;
		for(int i=1;i<n;++i) x[sa[i]]= y[sa[i-1]]==y[sa[i]]&&sa[i-1]+k<n&&sa[i]+k<n&&y[sa[i-1]+k]==y[sa[i]+k]? p-1:p++;
		if(p>=n) break;
		else m=p;
	}
	for(int i=0;i<p;++i) printf("%d ",sa[i]+1); printf("\n");
	int k=0;
	for(int i=0;i<n;++i) {
		if(!x[i]) {
			k=0; continue;
		}
		if(k) k--;
		int j=sa[x[i]-1];
		while(s[i+k]==s[j+k]) k++;
		height[x[i]]=k;
	}
	for(int i=1;i<n;++i) printf("%d ",height[i]);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章