高度数组

1. 假设字符串尾 "ABABABB"

那么它的所有后缀为:

ABABABB

BABABB

ABABB

BABB

ABB

BB

B

将上面的所有后缀排好序之后变成:

ABABABB

ABABB

ABB

B

BABABB

BABB

BB

高度数组为所有后缀排好序之后的相邻两个后缀之间的最大公共前缀

比如height[1],看下标为1的后缀ABABB与上一个下标0的后缀ABABABB,最大公共前缀为ABAB,四个,那么height[1] = 4

其余的也是一样,那么可以得到高度数组为height[] = {0,4,2,0,1,3,1}

2. 使用代码描述

① 假设字符串为ABABABB(str),rank为下标的排名数组,rk[2] = 3表示下标为2的后缀排名是3,已经把字符串str的所有后缀排好序之后的数组为sa[](sa[3] = 5表示排名为3的后缀后缀下标为5)

先把外层循环搞定i从0-src.length-1

因为原来的sa数组是按照字符串相同排名相同,现在调整排名为不重复的排名,重新排名后得到数组rk

紧扣循环中的下标i,得到下标为i的排名rk[i] 在得到该排名的上一次排名rk[i]-1

(存在的规律是上一个下标i假如有k个公共前缀,并且k>0,那么下一个下标至少有一个k-1个公共前缀,那么前k个字符是不用比较的)

具体的代码如下:

public class Main {
	public static int [] getHeight(String src,Suff sa[]){
		//高度数组就是下标为k的与k-1的子串公共的前缀数量
		int height[] = new int[src.length()];
		int rk[] =  new int[src.length()];
		//恢复不重复的排名
		for(int i = 0;i<src.length();i++){
			rk[sa[i].index] = i;
		}
		
		int rk_i;
		int rk_i_1;
		int k = 0;
		for(int i = 0;i<src.length();i++){
			rk_i = rk[i];
			if(rk_i==0){
				height[0] = 0;
				continue;
			}
			//下标为i的排名的上一个排名
			rk_i_1 = rk_i - 1;
			//求出排名为rk_i_1的下标
			int j = sa[rk_i_1].index;
			if(k>0)k--;
			for(;j+k<src.length()&&i+k<src.length();k++){
				if(src.charAt(j+k)!=src.charAt(i+k)){
					break;
				}
			}
			height[rk_i] = k;	
		}
		return height;
	}
}

② 其中绑定了下标的类的代码如下:

import java.util.Arrays;
public class Suff implements Comparable<Suff>{
    public String str;
    public int index;//后缀的起始下标
    public Suff(String str, int index) {
    	 this.str = str;
    	 this.index = index;
	}
    
	public String toString() {
	      return "Suff{" +
	          "char='" + str + '\'' +
	          ", index=" + index +
	          '}';
	}
	  
	//直接对所有后缀排序,因为字符串的比较消耗O(n),所以整体为n^2log(n)
	public static Suff[] getSa(String src){
		int strLength = src.length();
		//sa是排名到下标的映射,即sa[i] = k说明排名为i的后缀是从k开始的
		Suff suffixArray[] = new Suff[strLength];
		for(int i =0;i<strLength;i++){
			String suffI = src.substring(i);
			suffixArray[i] = new Suff(suffI,i);
		}
		Arrays.sort(suffixArray);//依据suff的排序规则进行排序
		return suffixArray;
	}

	@Override
	public int compareTo(Suff o2) {
		  return this.str.compareTo(o2.str);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值