📜  找到没有重复字符的给定字符串的后缀数组(1)

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

找到没有重复字符的给定字符串的后缀数组

后缀数组是一个非常有用的数据结构,它可以用于字符串匹配、字符串排序等问题。而找到没有重复字符的给定字符串的后缀数组则可以用于解决一些特殊问题,如找到最长的没有重复字符的子串等。

算法思路

为了找到没有重复字符的给定字符串的后缀数组,我们可以使用后缀排序算法。后缀排序算法常见的就有基数排序算法和SA-IS算法,这里我们采用后者作为示例。

我们首先需要对字符串进行一些预处理,将其转换为一系列数字。具体来说,我们可以将每个字符映射为其ASCII码值,然后再加上一个小于所有字符对应的码值的数,以保证排序时不会出现负数。

然后我们可以使用SA-IS算法对这个数字序列进行后缀排序。在排序完成后,得到的后缀数组即为没有重复字符的给定字符串的后缀数组。

代码实现

下面是使用C++实现的代码片段:

const int N = 10010;
int sa[N], rk[N], ht[N], tp[N], buc[N];
void get_sa(int *s, int n) {
    int m = 128;
    for (int i = 0; i < m; ++i) buc[i] = 0;
    for (int i = 1; i <= n; ++i) ++buc[rk[i] = s[i]];
    for (int i = 1; i < m; ++i) buc[i] += buc[i-1];
    for (int i = n; i; --i) sa[buc[rk[i]]--] = i;
    for (int k = 1; k <= n; k <<= 1) {
        int p = 0;
        for (int i = n; i > n-k; --i) tp[++p] = i;
        for (int i = 1; i <= n; ++i) if (sa[i] > k) tp[++p] = sa[i]-k;
        for (int i = 0; i < m; ++i) buc[i] = 0;
        for (int i = 1; i <= n; ++i) ++buc[rk[i]];
        for (int i = 1; i < m; ++i) buc[i] += buc[i-1];
        for (int i = n; i; --i) sa[buc[rk[tp[i]]]--] = tp[i];
        swap(rk, tp);
        int tot = rk[sa[1]] = 1;
        for (int i = 2; i <= n; ++i) {
            rk[sa[i]] = (tp[sa[i]] == tp[sa[i-1]] && tp[sa[i]+k] == tp[sa[i-1]+k]) ? tot : ++tot;
        }
        if (tot >= n) break;
        m = tot;
    }
}
void get_ht(int n) {
    int k = 0;
    for (int i = 1; i <= n; ++i) {
        if (rk[i] == 1) continue;
        if (k) --k;
        int j = sa[rk[i]-1];
        while (i+k <= n && j+k <= n && s[i+k] == s[j+k]) ++k;
        ht[rk[i]] = k;
    }
}
总结

本文介绍了如何找到没有重复字符的给定字符串的后缀数组,并给出了一种基于SA-IS算法的实现方法。需要注意的是,为了避免重复字符的出现,我们需要将字符映射为数字,并且必须采用适当的排序算法来处理数字序列。