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

来源:互联网 发布:js 鼠标滑动特效 编辑:程序博客网 时间:2024/05/01 19:43

后缀数组是解字符串问题的一个工具,后缀数组的构建复杂度为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[n];int[] y = new int[n];int[] c = new int[maxn];int[] sa = new int[n];//基数排序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();}}}