给定n个字符串,其中一个是另一个的子字符串吗?


9

假设我们得到了字符串的集合。我想知道这些字符串中的任何一个是否是集合中任何其他字符串的子字符串。换句话说,我想要一种用于以下任务的算法:ñ小号1个小号ñ

输入:小号1个小号ñ

输出:使得是和的子字符串,或者如果不存在这样的则为None一世Ĵ小号一世小号Ĵ一世Ĵ一世Ĵ

是否有一种有效的算法?

如果将“子字符串”替换为“前缀”,则存在一种有效的算法(对字符串进行排序,然后进行线性扫描以比较相邻的字符串;排序将确保子字符串相邻)。但是测试任何字符串是否为其他字符串的子字符串似乎更具挑战性。一个朴素的算法是遍历所有对,但这需要子字符串测试。有没有更有效的算法?一世ĴΘñ2

我猜我们可以称其为“所有对子字符串测试”或类似的名称。

我的最终目标是修剪集合,以便通过删除集合中其他子字符串的每个子字符串,使任何字符串都不是其他子字符串。


提示:后缀数组。
别名2014年

附带说明一下,如果在找到子字符串时将其删除,则不正确。它会更少。另外,由于较长的字符串不能出现在较短的字符串中,因此应按长度排序。再次,Θ n 2在这里是错误的。Θñ2Θñ2
亚历克西斯·威尔克

@AlexisWilke,是正确的:这是最坏情况下子字符串测试的数量(最坏情况是没有字符串是任何其他子字符串的子字符串)。按长度排序仅给您2的因数,这不会影响渐近线。Θñ2
DW

Answers:


6

您可以在线性时间内构建后缀树,并检查是否存在与完整字符串相对应的内部节点(每个节点的恒定时间)。

更具体地说,假设我们给出的字符串s1个sñΣ

  1. 构建(广义)后缀树Ñ两两不同终端标记$ 1... $ ÑΣ s1个$1个s2$2sñ$ññ$1个$ñΣ

    使用Ukkonen的算法,可以在线性时间内完成;所有字符串长度的总和为线性。

  2. 一世Ĵs一世[Ĵ|s一世|]s一世ñ一世0

    这花费的时间在树大小上是线性的,而树大小本身在输入大小上是线性的。

  3. 一世0$一世一世0

    这又需要线性时间。

不同的终端标记并不是真正必要的。只要您在每个叶子上允许多个标签,用于终止所有字符串的单个字符串就足够了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.