给定HashMap,我想检索其值包含给定子字符串s的所有条目(非区分大小写)。我在Suffix树(trie)的行上寻找子串索引思想,它们只适用于前缀/后缀匹配。
答案 0 :(得分:0)
后缀树不仅适用于后缀匹配。您可以这样做:
hazelnut
和coconut
将共享代表nut
,ut
和{{1 }})让 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 ++中,但它仍然可以说明问题)。