📜  后缀数组|设置2(nLogn算法)(1)

📅  最后修改于: 2023-12-03 15:37:10.651000             🧑  作者: Mango

后缀数组 | O(nlogn)算法

什么是后缀数组

后缀数组是一种用于解决字符串问题的数据结构。它可以在O(nlogn)的时间复杂度内解决很多字符串相关的问题,比如最长公共子串,最长回文子串等。它是通过将字符串的所有后缀按字典序排序并保存其起始位置的一种方式实现的。

后缀数组的构造

后缀数组有多种构造方法,其中最简单的一种方法是通过对所有后缀进行排序来构建后缀数组。可以使用快速排序等高效的排序算法。但是,由于字符串长度通常很长,因此这种方法可能会导致O(n^2logn)的时间复杂度。

另一种更高效的构建方法称为倍增算法,在这种方法中,我们首先对所有单个字符的后缀进行排序,然后对长度为2的后缀,长度为4的后缀等进行排序,直到整个字符串的后缀都被排序。这种构造方法的时间复杂度为O(nlog^2n)。

后缀数组的应用
1. 等价类

后缀数组可以将一个字符串的所有后缀分为不同的等价类,其中两个后缀在同一类中当且仅当它们在原始字符串中的子串是相等的。这种分组可以被用来实现一些字符串相关的操作,比如查找最长重复子串、最长不重叠重复子串、最长回文子串等。

2. 查找模式串

后缀数组可以用于查找一个模式串在一个字符串中的出现位置。对于一个长度为m的模式串,我们可以首先将其在后缀数组中查找到一个前缀和模式串相等的后缀,然后向左或向右扩展来判断是否为匹配。

3. 查找最长公共前缀

后缀数组可以用于查找两个字符串的最长公共前缀。在后缀数组上,LCP(i,j)表示后缀i和后缀j的最长公共前缀长度。可以使用ST算法来快速查询LCP。

代码实现

以下是一个使用倍增算法构建后缀数组的简单代码实现:

def build_suffix_array(s):
    n = len(s)
    sa = [i for i in range(n)]
    rank = list(s)
    k = 1
    while k < n:
        tmp = [(rank[i], rank[i+k] if i+k < n else -1, i) for i in
                range(n)]
        tmp.sort()
        sa[tmp[0][2]] = 0
        for i in range(1, n):
            sa[tmp[i][2]] = sa[tmp[i-1][2]]
            if tmp[i][0:2] != tmp[i-1][0:2]:
                sa[tmp[i][2]] += 1
        rank = [sa[i] for i in range(n)]
        if rank[tmp[n-1][2]] == n-1:
            break
        k *= 2
    return sa

由于Python中的字符串是不可变的,因此我们必须使用一个字符串的列表作为输入。