【问题标题】:Complete Suffix Array完整的后缀数组
【发布时间】:2012-02-22 05:45:54
【问题描述】:

后缀数组将索引给定字符串列表的所有后缀,但如果您尝试索引所有可能的唯一子字符串怎么办?我对此有点陌生,所以这里有一个例子来说明我的意思:

给定字符串

abcd

后缀数组索引(至少在我的理解中)

(abcd,bcd,cd,d)

我想索引(所有子字符串)

(abcd,bcd,cd,d,abc,bc,c,ab,b,a)

我正在寻找一个后缀数组吗?如果是这样,我该怎么做才能索引所有子字符串?如果没有,我应该在哪里寻找?另外我会用谷歌来对比“所有子字符串”与“后缀子字符串”吗?

【问题讨论】:

标签: python string algorithm suffix-tree suffix-array


【解决方案1】:

后缀数组可以满足您的需要,因为每个子字符串都是其中一个后缀的前缀。具体来说,给定您的后缀数组

abcd bcd 光盘 d

并假设您正在查找子字符串“bc”,那么您可以通过查找所有以“bc”开头的后缀来找到它(在这种情况下只有一个“bcd”)。由于后缀数组是按字典顺序排序的,因此找到所有共享某个前缀的后缀对应于对后缀数组进行二分查找,结果将是后缀数组的一个连续范围的条目。

但是,也有使用后缀数组结合辅助数据结构的优化搜索方法,例如 LCP(最长公共前缀)数组或小波树。有关此类方法的描述,请参阅 Navarro 2007 年的调查 (DOI 10.1145/1216370.1216372)。

考虑到下面的 cmets,我建议将每个后缀与它所代表的 子字符串的数量结合起来。在像上面这样的简单示例中,这将是

4 abcd
3 bcd
2 bc
1 d

因为例如第一个后缀“abcd”代表了4个子串“a”、“ab”、“abc”、“abcd”。然而,在一个更复杂的例子中,比如字符串“abcabxdabe”,后缀数组的前两个条目将是

10 abcabxdabe
1 abe

因为第二个条目表示子串“a”、“ab”和“abe”,但“a”和“ab”也由第一个条目表示。

如何计算一个条目代表的子字符串的数量? --> 后缀的长度减去它与前一个后缀共有的最长前缀的长度。例如。在“abe”示例中,即 3(它的长度)减去 2(“ab”的长度,它与前一个条目共享的最长前缀)。因此,这些数字可以通过后缀数组一次性生成,如果您还生成了 LCP(最长公共前缀)数组,则速度会更快。

下一步是生成累积计数:

10 abcabxdabe
11 abe
16 abxdabe
...

然后找到一种有效的方法来利用累积的计数。例如。如果要按字典顺序获取第 13 个子字符串,则必须找到累积计数大于或等于 13 的第一个条目。这将是上面的“16 abxdabe”。然后去掉它与前一个条目共享的前缀(产生“xdabe”),然后跳转到第2个字符之后的位置(因为前一个条目已经累积计数11,并且13-11==2),所以你得到“ abxd" 按字典顺序排列为第 13 个子字符串。

【讨论】:

  • 很好,我已经想到了这一点,但是如果我想按字典顺序查找第 n 个子字符串怎么办。我不必遍历数组并为非后缀子字符串添加条目吗?因为如果我检索索引 n 处的子字符串,这只会计算后缀。我有任何意义吗?对不起,如果我不这样做..
  • 我明白了,是的,这是有道理的。我最初误解了“索引”的意思。但我相信您所要求的也可以使用稍微扩展的后缀数组来完成。具体来说,您将数组中的每个后缀与一个数字组合在一起,该数字表示它代表多少个唯一子字符串。 它所代表的子串基本上是它所包含的前缀,减去前面的后缀已经表示的前缀。我将通过编辑答案来描述这个细节。
  • 哇,感谢您提供的优雅解决方案。我目前正在生成 LCP 阵列,所以这看起来应该可以正常工作。非常感谢您的帮助,如果成功了,我会通知您!
  • 很好的解释。我真的很喜欢这种类型的答案。
【解决方案2】:

正如已经回答的那样,子字符串是后缀的前缀。有时您可能想另辟蹊径并获得前缀的后缀。

除此之外,还不清楚您要使用“唯一子字符串”寻找什么。我建议你查一下这些词:类型、令牌、最大值、超最大值。在后缀数组文献中找到这些应该没有问题。

【讨论】:

  • 我突然想到有一种更有趣的方式来表达同样的事情。启动并运行后缀数组后,收集有关后缀数组的论文语料库并在您的程序中运行它们。然后,您将看到该领域使用了哪些技术词汇。如果你睁大眼睛,你可能会得到一些惊喜。当然,如果你自己写一篇论文,那么通过后缀数组运行它。并且不要忘记具有特殊属性的数学类型的字符串。享受!使用后缀数组更好地生活!
  • 您的 SA 语料库必须包括 Abouelhoda 等人。我会添加 Kim 等人的“线性化后缀树”论文。后者有一个很好的“文献评论”部分,这确实有助于了解 Abouelhoda 的一些更晦涩的部分。从“休闲数学”的角度来看后缀数组,请阅读 Klaus Shürman 的书。
  • 您的 SA 语料库必须包括 Abouelhoda 等人。我会添加 Kim 等人的“线性化后缀树”论文。后者有一个很好的“文献评论”部分,这确实有助于了解 Abouelhoda 的一些更晦涩的部分。对于从“休闲数学”的角度来看的后缀数组,请阅读 Klaus Shürman 的书。并且(额外的特别提示)查看 Gusfield 在加州大学戴维斯分校的录像带讲座。
  • 我所说的唯一子字符串的意思是:假设我有一个包含 2 个字符串的数组:[abcd,adcb]。首先我会找到 abcd 的子串 (a,ab,abc,abcd,b,bc,bcd,c,cd,d) 然后我会找到 adcb 的子串 (a,ad,adc,adcb,d,直流,直流,c,cb,b)。然后我会采用这些集合的并集:(a,ab,abc,abcd,b,bc,bcd,c,cd,d,ad,adc,adcb,dc,dcb,cb)。这些将是字符串数组的唯一子字符串。
  • 感谢文献建议,我一定会尽快看一看,听起来很吸引人。
【解决方案3】:

您应该使用“Trie”的变体。本质上,如果您有 ABCD,则创建路径合并的树:root->A->B->C->D、root->B->C->D、root->C->D 和 root ->D。现在,在每个节点上保留一个位置列表,其中字符串 root->.->.->node 被观察到。

【讨论】:

  • 谢谢,我也会看看这个替代方法。
猜你喜欢
  • 2014-08-19
  • 2012-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
  • 2012-01-22
相关资源
最近更新 更多