后缀数组、名次数组-JavaScript

后缀数组sa,告诉你,排第几的是谁

名次数组rank, 告诉你,你排第几

height数组,i为排名,排名为i的后缀为sa[i]

height[i]表示后缀sa[i]和sa[i-1]的最长公共前缀的长度n

 

//二分查找法,返回最接近的位置和实际位置
function binary_find(id,hasSortArr){
let l=0,r=hasSortArr.length;
let index=-1;
while(r-l>0){
const m=(l+r)>>1;
const mid=hasSortArr[m]
//比较下坐标大小
const order=id>mid?1:(id
if(order===1){
l=Math.max(l+1,m)
}else if(order===-1){
r=Math.min(r-1,m)
}else{
l=r=m;
index=m;
}
}
return [(l+r)>>1,index]
}
//二分法去重排序
function binary_sort(str) {
const sa=[]
for(let i=0;i const [n,index]=binary_find(str[i],sa);
if(index===-1){
sa.splice(n,0,str[i])
}
}
return sa;
}

//后缀数组sa,告诉你,排第几的是谁
//名次数组rk, 告诉你,你排第几
//SA[i]表示排名为i的后缀、rk[i]表示起始位置的下标为i的后缀的排名
////获取后缀数组
function getSa(str) {
let arr=str.split('');
const sLen=arr.length;//总共排名长度
let uarr=binary_sort(arr);//获取排序去重后的
const rk=[];
let run=true;
let len=1;//最长相似字符
while (run){
const map={}
uarr.forEach(function (v,k) {
map[v]=k+1;
})
for(let i=0;i rk[i]=map[arr[i]];
}
if(uarr.length for(let i=0;i const fz=i+len arr[i]=rk[i]*(uarr.length+1)+fz;
}
len=len*2;
uarr=binary_sort(arr)
}else{
run=false;
}
}
//SA[i]表示排名为i的后缀、rk[i]表示起始位置的下标为i的后缀的排名
const sa=[]
rk.forEach(function (v,k) {
sa[v-1]=k;
})
return sa
}
//SA[i]表示排名为i的后缀
function getRkBySa(sa){
const rk=[]
sa.forEach(function (v,k) {
rk[v]=k;
})
return rk;
}
//height[i] 表示排名为i的公共前缀长度
//h[i] 表示起始位置的下标为i的公共前缀长度
function calheight(s,rk,sa) {
const h=[];
const height=[];
for (let i=0;i let k=0;
if(rk[i]>0){
const j=sa[rk[i]-1]
while (s[i+k]===s[j+k]){
k++
}
}
height[rk[i]]=k;
h[i]=k
}

return {height,h};
}

//demo
const str1='* 4444222233323333';
////获取后缀数组
const sa=getSa(str1);
const rk=getRkBySa(sa);
const {height,h}=calheight(str1,rk,sa)
console.log(sa,rk,height,h)

 //输出

[
1, 0, 6, 7, 8, 9, 13,
17, 12, 16, 11, 15, 10, 14,
5, 4, 3, 2
] [
1, 0, 17, 16, 15, 14, 2,
3, 4, 5, 12, 10, 8, 6,
13, 11, 9, 7
] [
0, 0, 0, 3, 2, 1, 4,
0, 1, 1, 2, 2, 3, 3,
0, 1, 2, 3
] [
0, 0, 3, 2, 1, 0, 0,
3, 2, 1, 3, 2, 1, 4,
3, 2, 1, 0
]

你可能感兴趣的:(后缀数组、名次数组-JavaScript)