在一次采访中,我被要求提出可以容纳数百万个模式的数据结构,并通过它们快速搜索以找到最长的匹配模式。
例如,模式如下:
1- 8876 8893 87 | true
2- 8876 889 | false
3- 8876 8 | false
4- 887 | true
输入是一个至少有2位且最多18位的数字,我们需要从数据结构中找到最长的匹配模式,并在最后提取布尔值。
例如,8876 8893 9943 53
与1
匹配,并返回true
。 8876 8397 5430 74
与3
匹配,并返回false
。
我的回答是使用一棵树,每个级别都有key value
对的列表。作为数字和值的键是null或等于布尔值,具体取决于它是否是模式的结尾。像:
# matching 8875
# start the search by first digit
[..., (7, null), (8, null), (9, null)]
^
[..., (7, null), (8, null), (9, null)]
^
[..., (7, true), (8, null), ...]
# at the last step because we don't have a pattern
# to match the digit 5, we return the `true` from (7, true)
具有挑战性的部分是,模式非常多。数以百万计。这有什么好处吗?如果没有,你的建议是什么。
答案 0 :(得分:3)
非常好的数据结构非常适合您描述的问题,即许多条目共享公共前缀(和/或后缀)的集合结构,以及基于共享前缀执行搜索的位置是Trie。
在computer science中, trie ,也称为数字树,有时也称为radix tree或前缀树(如它们可以通过前缀来搜索,是一种有序的树数据结构,用于存储动态集或关联数组,其中键通常是字符串。与二叉搜索树不同,树中没有节点存储与该节点关联的密钥;相反,它在树中的位置定义了与之关联的键。节点的所有后代都具有与该节点关联的字符串的公共prefix,并且根与空字符串相关联。值通常不与每个节点相关联,只与叶子和一些与感兴趣的键对应的内部节点相关联。有关前缀树的空间优化表示,请参阅compact prefix tree。
具体来说,紧凑型前缀树或 patricia trie 似乎非常适合您的问题。
鉴于所提到的类型的尝试通常用于存储与键相关联的值,如果您的问题不需要(即,您不需要存储输入模式字符串的原始索引并在搜索中返回该值),有一个密切相关的解决方案可能更适合。正如@JimMischel在评论中指出的那样, Aho–Corasick string matching algorithm 构建了一个类似于trie的结构,并在内部节点之间增加了链接。如果要匹配的模式集是固定的,并且构建了数据结构,那么对于搜索,其运行时间在输入长度和匹配条目数方面是线性的。
中讨论了这个问题答案 1 :(得分:0)
你可以考虑实现wu-manber,这对代码和内存的效率也很简单。