扫描文本并检查它是否包含指定列表中的单词

时间:2012-11-22 16:19:51

标签: string algorithm

要求

  1. 目前我们有一个包含超过一万个关键字或句子的列表(数字为N)
  2. 输入为长字符串,长度为L
  3. 问题:检查字符串是否包含给定列表中的关键字或句子

    问题可以描述为wikipedia上的字词过滤器,但我在该页面上找不到任何算法。解决这个问题的最简单方法是迭代所有关键字或句子,每次检查长文本是否包含这样的子字符串。由于我们有很多关键字,也考虑到长文本,性能非常糟糕。它使用O(NL)时间

    似乎应该在O(L)中完成更好的解决方案。任何人都可以对此提出一些建议吗?

1 个答案:

答案 0 :(得分:4)

这个问题有几种方法,时间复杂度为O(M + L),其中L是字符串的长度,M是所有模式的组合长度:

  1. Aho–Corasick string matching algorithm
  2. 使用suffix tree为字符串构造Ukkonen's algorithm,然后找到每个模式与此后缀树的匹配。
  3. 为一组模式构造generalized suffix tree,然后找到输入字符串与此后缀树之间的匹配。
  4. 为字符串构造Suffix array,并使用它来搜索每个模式。该方法具有时间复杂度O(M + L + N log L),其中N是模式的数量。
  5. Commentz-Walter algorithm
  6. 您可以在本书中找到所有这些算法的详细信息(Commentz-Walter算法除外):Algorithms on Strings, Trees and Sequences by Dan Gusfield


    如果您可以明确地从输入字符串中提取单独的单词/句子,则可以使用几种不同的(更简单的)方法。

    1. 准备一个Bloom filter,其大小足以保证N个模式的误报概率低。添加到Bloom过滤器位,由关键字/句子的散列函数确定。然后扫描字符串,提取连续的单词/句子,并检查是否可以在Bloom过滤器中找到这些单词/句子。仅当Bloom过滤器中存在单词/句子时,才在模式列表中搜索它。该算法具有预期的时间复杂度O(M + L)并且节省空间。
    2. 将所有模式插入哈希集。然后扫描字符串,提取连续的单词/句子,并检查它们中是否有任何一个在哈希集中。这具有相同的预期时间复杂度O(M + L),比Bloom过滤器方法简单,但不节省空间。
    3. 将所有模式插入基数树(trie)。然后用它来搜索字符串中的单词/句子。这与广义后缀树方法没有太大差别,但更简单并且具有更好的性能。它具有最坏情况时间复杂度O(M + L),可能比Bloom过滤器或散列集方法稍慢,并且如果需要可以使其非常节省空间。