后缀数组 nLogN 算法2024年8月28日 | 阅读 7 分钟 特定字符串的所有后缀都排列在一个后缀数组中。这个概念与后缀树类似,后缀树是文本所有后缀的压缩树。 后缀数组是一种基本数据结构,被许多处理字符串的算法所使用。它显示了一个给定字符串的所有后缀的数组,这些后缀已经按字典顺序排列。使用最有效的方法构建后缀数组所需的时间复杂度通常是 O(n log n),其中 n 是输入文本的长度。 使用 nlogn 算法构建后缀数组使用暴力法,时间复杂度为 O(n^2 logn)。 对此进行了修改,并构建了一种优化的方法,其时间复杂度为 O(nlogn)。 基于 DC3(Difference Cover 3)技术的“偏斜算法”是一种众所周知的以 O(n log n) 时间复杂度构建后缀数组的方法。下面是该算法的一般描述: 1. 预处理
2. 构建初始后缀数组
3. 诱导排序
4. 合并步骤
尽管从头开始实现偏斜方法可能很困难,但有一些开源工具和实现可供您使用。SuffixArray (C++)、SuffixArray.jl (Julia) 和 pysuffixarray (Python) 是几个著名的库。 例如,SA-IS(后缀数组诱导排序)方法是另一种以 O(n log n) 时间复杂度构建后缀数组的算法,但偏斜算法因其易用性和实际效率而经常受到青睐。 示例让我们看一个例子,以便更好地理解如何为给定字符串创建后缀数组。以“banana$”一词为例。为了表示字符串已结束,我们附加特殊字符“$”(它小于所有其他字符)。DC3 算法用于按如下方式为该字符串创建后缀数组: 步骤 1 预处理 使用其 ASCII 值,字符串“banana$”中的字符可以表示为整数: 步骤 2:创建初始后缀数组 使用基数排序对字符串的后缀进行排序。下面列出了后缀及其初始位置: 后缀
排序后,后缀重新排列如下:
步骤 3:诱导排序 后缀根据其类型(S 和 L)递归排序。在此阶段,我们区分 S 型和 L 型字符。S 型字符是小于其后字符的字符,L 型字符是大于其后字符的字符。为简单起见,特殊字符“$”被视为 S 型字符。 36(索引 6 处)和 97(索引 1、3、5 处)是 S 型(S)字符。 98(索引 0 处)和 97(索引 2、4 处)是 L 型(L)字符。 我们从末尾开始递归地对 S 型和 L 型后缀进行排序。结果是以下已排序的后缀: 后缀 36(从索引 6 开始) 97 36(从索引 5 开始) 97 110 97 36(从索引 3 开始) 97 110 97 110 97 36(从索引 1 开始) 110 97 36(从索引 4 开始) 110 97 110 97 36(从索引 2 开始) 98 97 110 97 110 97 36(从索引 0 开始) 步骤 4:合并步骤 在最后阶段,将诱导排序产生的两个已排序数组合并,同时考虑后缀的初始位置。 合并后缀 6(从索引 6 开始) 5 6(从索引 5 开始) 3 4 5 6(从索引 3 开始) 1 2 3 4 5 6(从索引 1 开始) 4 5(从索引 4 开始) 2 3(从索引 2 开始) 0 1 2 3 4 5 6(从索引 0 开始) 字符串“banana$”的最终后缀数组是 [6, 5, 3, 1, 4, 2, 0]。这些数字表示已排序后缀在原始字符串中的起始位置。值得注意的是,表示字符串末尾的特殊字符“$”对应于已排序数组中最短的后缀。 这是如何为给定字符串创建后缀数组的简单示例。在实际使用中,该技术即使对于非常长的字符串也有效。 nlogn 算法的实现SA-IS 或偏斜算法必须完全用 C 语言实现,这超出了单个答案的范围。不过,我可以为您提供 C 语言中该算法的精简版本。尽管此实现可能不如优化的库有效,但它将帮助您理解算法的结构。 C 代码 输出 Suffix Array for the string "banana$": 6: $ 5: a$ 3: ana$ 1: anana$ 0: banana$ 4: na$ 2: nana$ Time Complexity: O(nlogn). 下一个主题后缀树介绍: |
我们请求您订阅我们的新闻通讯以获取最新更新。