后缀数组
本文最后更新于:2024年2月12日 晚上
https://www.geeksforgeeks.org/suffix-array-set-2-a-nlognlogn-algorithm/?ref=gcse
后缀数组的$O(nlognlogn)$实现 ,基于倍增和排速
import java.util.Arrays;
/**
* @Author: merickbao
* @Created_Time: 2022-03-23 16:31
* @Description: 后缀数组 :https://www.geeksforgeeks.org/suffix-array-set-2-a-nlognlogn-algorithm/
*/
public class SuffixArray {
// 后缀数组节点
class Node implements Comparable<Node> {
int idx; // 后缀在原始字符串中的起点
int rank; // 该后缀的排名
int next; // 第二个比较位的排名
public Node(int idx, int rank, int next) {
this.idx = idx;
this.rank = rank;
this.next = next;
}
@Override
public int compareTo(Node o) {
if (o.rank == this.rank) return Integer.compare(this.next, o.next);
return Integer.compare(this.rank, o.rank);
}
}
public int[] getSuffixArray(String s) {
int n = s.length();
Node[] suffix = new Node[n];
// 新建节点:最先以单个字母ascii码来排名
for (int i = 0; i < n; i++) {
suffix[i] = new Node(i, s.charAt(i) - 'a', 0);
}
// 更新下一个节点rank
for (int i = 0; i < n; i++) {
// 如果下一个节点超过数组长度,置为-1
suffix[i].next = (i + 1 < n ? suffix[i + 1].rank : -1);
}
// 第一次排序:根据后缀前两位字符排序
Arrays.sort(suffix);
// 开始倍增的进行排序 : 4, 8, 16 ...
int[] ind = new int[n]; // 辅助数组:用来保存下一个比较位的排名
for (int len = 4; len < 2 * n; len *= 2) {
// 首先根据排序结果重新分配排名
int rank = 0, prev = suffix[0].rank;
suffix[0].rank = 0;
ind[suffix[0].idx] = 0;
for (int i = 1; i < n; i++) {
// 两个节点暂时还不能分出排名,置为相同的排名
if (suffix[i].rank == prev && suffix[i].next == suffix[i - 1].next) {
prev = suffix[i].rank;
suffix[i].rank = rank;
} else {
prev = suffix[i].rank;
suffix[i].rank = ++rank;
}
ind[suffix[i].idx] = i;
}
// 分配下一个比较位的排名
for (int i = 0; i < n; i++) {
int nextP = suffix[i].idx + len / 2;
suffix[i].next = nextP < n ? suffix[ind[nextP]].rank : -1;
}
// 根据前 len / 2 个字符排序
Arrays.sort(suffix);
}
int[] suffixArray = new int[n];
for (int i = 0; i < n; i++) {
suffixArray[i] = suffix[i].idx;
}
return suffixArray;
}
}
本文作者: MerickBao
本文链接: https://merickbao.top/post/%E7%AE%97%E6%B3%95/%E8%BF%9B%E9%98%B6%E7%AE%97%E6%B3%95/%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!