子字符串搜索HashMap值

时间:2016-06-28 00:20:53

标签: c# string algorithm hashmap suffix-tree

给定HashMap,我想检索其值包含给定子字符串s的所有条目(非区分大小写)。我在Suffix树(trie)的行上寻找子串索引思想,它们只适用于前缀/后缀匹配。

1 个答案:

答案 0 :(得分:0)

基于广义后缀树的解决方案

后缀树不仅适用于后缀匹配。您可以这样做:

  • 使用哈希表中的每个条目构建一个通用后缀树。请注意,您必须将所有字符串转换为任意大小写以便忽略大小写。在构造期间,使用共享它的字符串集标记每个叶子(例如,字符串hazelnutcoconut将共享代表nutut和{{1 }})
  • 从根开始:
    • 使用子串 s 向下走树(转换为第一步中选择的大小写):最终处于隐式状态(即在边缘的中间)或显式状态(你最终进入节点 N )。
    • 如果您处于隐式状态,只需占用您所在边缘的目标节点,让我们调用该节点 N
  • 计算您可以从 N 到达的所有树叶的字符串集的并集:您得到一组字符串 S
  • S 是哈希表中所有字符串的集合,其中包含子字符串 s

复杂性分析

K 成为表格中的字符串数量。设 L i 是字符串 S i 的相应长度,让 L =ΣL< sub> i 。树的构造将是 O(L)

向下走到节点 N O(长度)

现在更棘手的部分开始了。列出节点可以访问的所有叶子不是线性的,但它不会太麻烦。

L max = max(L i ,然后你可以走最多到达每一片叶子> L max 节点,更准确地说,如果从先前定义的节点 N 开始,您将到达的每个子叶子N 最多 L(s)= L max - length(s)步骤。

N 开始的子树也具有通用后缀树的结构。它最多代表 K 长度最多 L(s)的字符串。这些字符串中的任何一个最多都有 L(s)个叶子。所以迭代它们最多只是 O(K.L(s) 2

计算每个这样的叶子中的一组字符串的并集最多是 O([K.L(s)] 2 。 (实际上它将更接近 O(KL(s) 2 ,因为如果每个叶子都包含其中的所有原始 K 字符串设置,那么根据 N 的子树中只有 L(s)叶子。

这导致了最糟糕的案例复杂性:

  

O(L +长度(s)+ [K.L(s)] 2

但真正的使用复杂性将更接近:

  

O(L +长度(s)+ K. [L(s)] 2

标准方法(迭代每个字符串并在每个字符串中搜索 s )是:

  

O(Σ(L i + length(s)))= O(L + K.length(s))

但等等......我们总是寻找子串 s !因此, KMP算法的预处理只能进行一次......这降低了这种方法的复杂性:

  

O(L + length(s))

但是,为了从这样的优化中受益,您必须自己编写而不是使用标准实现...

结论

假设您只需要在地图上测试一个字符串 s ,那么天真的解决方案很容易实现,易于理解,其整体复杂性不仅更好基于后缀树的方法, 最优 。所以你可以自信地坚持下去。

但是,如果你必须测试字符串 s j 的大量 K s ,那么后缀树方法可以更好,因为它的整体复杂性最多:

  

O(L + K s 。(max(length(s j ))+ [K.max(L(s j < /子>)] 2 ))

而KMP方法将导致总体复杂性:

  

O(K s .L +Σ(长度(s j )))= O(K s 。[ L + max(长度(s j ))])

请注意,由于后缀树是一种树状结构,如果它没有巧妙设计,内存访问和分配将会发挥作用并严重影响运行时间。

如果你愿意,我可以用一个例子(在C ++中,但它仍然可以说明问题)。