您的位置:首页 > 其它

后缀数组,Manber & Mayer 倍增算法

2012-11-17 20:57 141 查看
后缀数组是解字符串问题的一个工具,后缀数组的构建复杂度为O(NLogN),在后缀数组的基础上进行模板匹配的复杂度为O(MLogN)。下面的JAVA代码适用于只包含0-255之间字符的字符串的后缀数组的构建。

参考文献:《算法竞赛入门经典训练指南》P221,刘汝佳,陈锋

package ProgrammingContest;

public class ArrayOfSuffix {

public static int[] calculateSA(String str) {

int n = str.length();
int m = 256;
int maxn = (n>m)?n:m;
int[] x = new int
;
int[] y = new int
;
int[] c = new int[maxn];
int[] sa = new int
;

//基数排序
for ( int i=0; i<m; i++ ) c[i] = 0;
for ( int i=0; i<n; i++ ) c[x[i]=str.charAt(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;

//Manber & Myers 倍增算法
for ( int k=1; k<=n; k <<= 1 ) {

//利用sa按第二关键字排序,原x后缀变成x-k后缀的第二关键字
int p = 0;
for ( int i=n-k; i<n; 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[y[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];

//重新统计基数
int[] tmp = x; x = y; y = tmp;
p = 1; x[sa[0]] = 0;
for ( int i=1; i<n; i++ ) {
int r = ((sa[i-1]+k)<n)?y[sa[i-1]+k]:0;	//后缀i-1的第二关键字
int s = ((sa[i]+k)<n)?y[sa[i]+k]:0;		//后缀i的第二关键字
if ( y[sa[i-1]] == y[sa[i]] && r == s ) {
x[sa[i]] = p-1;
} else {
x[sa[i]] = p++;
}
}

if ( p >= n ) break;
m = p;

}

return sa;
}

//测试
public static void main(String[] args) {
String[] strs = { "aabaaaab", "banana" };
for ( String s : strs ) {
int[] sa = calculateSA(s);
for ( int x : sa ) {
System.out.printf("%d ",x);
}
System.out.println();
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: