【问题标题】:Suffix Array construction in nlogn time [closed]在 nlogn 时间内构建后缀数组 [关闭]
【发布时间】:2020-08-29 12:37:53
【问题描述】:

我正在尝试通过此链接了解后缀数组的工作原理 - https://www.geeksforgeeks.org/suffix-array-set-2-a-nlognlogn-algorithm/。在这个链接中,我了解了代码和程序,首先按 2 个字符排序,然后按 4 个字符和 8 个字符排序,依此类推。 我没有得到的是 - 限制被视为 2*n。这是为什么 ?如果字符串的长度为 6,则只需 1 次迭代就足够了。相关代码sn-p如下。 ALso 相同的链接还提供了另一篇斯坦福大学关于后缀数组的论文,它完全在我脑海中浮现。论文相关链接为-https://web.stanford.edu/class/cs97si/suffix-array.pdf。在本文中的后缀数组(第 5 页)部分下,如果有人可以更直观地解释该论文中编写的示例和 C++ 代码。真的很有帮助。

for (int k = 4; k < 2*n; k = k*2) 
    { 
        // Assigning rank and index values to first suffix 
        int rank = 0; 
        int prev_rank = suffixes[0].rank[0]; 
        suffixes[0].rank[0] = rank; 
        ind[suffixes[0].index] = 0; 

        // Assigning rank to suffixes 
        for (int i = 1; i < n; i++) 
        { 
            // If first rank and next ranks are same as that of previous 
            // suffix in array, assign the same new rank to this suffix 
            if (suffixes[i].rank[0] == prev_rank && 
                    suffixes[i].rank[1] == suffixes[i-1].rank[1]) 
            { 
                prev_rank = suffixes[i].rank[0]; 
                suffixes[i].rank[0] = rank; 
            } 
            else // Otherwise increment rank and assign 
            { 
                prev_rank = suffixes[i].rank[0]; 
                suffixes[i].rank[0] = ++rank; 
            } 
            ind[suffixes[i].index] = i; 
        } 

        // Assign next rank to every suffix 
        for (int i = 0; i < n; i++) 
        { 
            int nextindex = suffixes[i].index + k/2; 
            suffixes[i].rank[1] = (nextindex < n)? 
                                  suffixes[ind[nextindex]].rank[0]: -1; 
        } 

        // Sort the suffixes according to first k characters 
        sort(suffixes, suffixes+n, cmp); 
    } 

    // Store indexes of all sorted suffixes in the suffix array 
    int *suffixArr = new int[n]; 
    for (int i = 0; i < n; i++) 
        suffixArr[i] = suffixes[i].index; 

    // Return the suffix array 
    return  suffixArr; 
} 

【问题讨论】:

    标签: string algorithm c++11 suffix-array


    【解决方案1】:

    我认为从一个小例子开始总是好的:

    让我们选择“ABABAC”。

    第一轮:

    在第一轮中,我们分配了以下排名:(0,1,0,1,0,2),因为这是长度为 1 的子字符串的顺序。

    第二轮:

    第二轮我们对第一轮的邻居进行排序: ((0,1),(1,0),(0,1),(1,0),(0,2),(2,-1)) // -1 表示没有字符

    如果你按字典顺序排序,你会得到这个顺序 (0,1),(0,2),(1,0),(2,-1)。所以你说:

    • (0,1) -> 0 (AB)
    • (0,2) -> 1 (AC)
    • (1,0) -> 2 (BA)
    • (2,-1) -> 3 (C)

    所以这一轮以这个顺序结束:(0,2,0,2,1,3)

    第三轮:你选择对,但不选择邻居,因为每一步你都应该将距离乘以 2。所以这一轮你设置了第 i 个索引和前一个第 (i+2) 个索引的对回合最终订单。

    ((0,0),(2,2),(0,1),(2,3),(1,-1),(3,-1))。如果您对此进行排序,您将获得以下排名:

    • (0,0) -> 0 (ABAB)
    • (0,1) -> 1 (ABAC)
    • (1,-1) -> 2 (AC)
    • (2, 2) -> 3 (BABA)
    • (2,3) -> 4 (BAC)
    • (3,-1) -> 5 (C)

    (0,3,1,4,2,5) 这是后缀的最终顺序,因为现在每个位置都不同,您不需要再执行一步,但下一步我们将使用(i-th, (i+4)-th) 对。

    我认为这个算法的复杂性是 O(nlog^2n),因为我们使用了 n 次排序日志。我认为后缀树可以解决这种复杂度为 O log n 的问题,但实现起来要困难得多。

    你的问题:

    “限制被视为2 * n。这是为什么?如果字符串的长度是6只有1”

    总是不够。例如,如果字符串是“AAAAAB”,那么在第一次迭代之后,您将从每个位置计算前 4 个字符的顺序,所以第一个和第二个位置仍然相同,因为它是“AAAA”,所以你需要一个更多的迭代可以严格排序。

    【讨论】:

    • 感谢 Istvan 的直观回复。现在更有意义了。
    猜你喜欢
    • 1970-01-01
    • 2011-11-19
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    相关资源
    最近更新 更多