给出字符串映射,例如:
{'ABC': 'BCD', 'key': 'book',........}
无限的文字流,例如:
"Sally had a key and a book with the ABC..."
将与字符串映射中的键匹配的每个标记替换为其对应的值的有效算法是什么?
输出:
"Sally had a book and a book with the BCD..."
除了简单地拆分传入的令牌并查询字符串映射以进行收容(O(1)操作)之外,还能做得更好吗?
代码将驻留在网络服务器上 - 用户获得转换输出的速度越快越好。
答案 0 :(得分:1)
嗯,您正在寻找的算法至少与您正在阅读的令牌数量呈线性关系(因为您最多只会对每个令牌进行一定数量的操作)你的流中的令牌),所以那里没有任何改进,因为我假设输入流中没有特殊的冗余或模式(我们可以滥用以提高效率)。
对于地图,最有效的解决方案可能是地图键上的二元搜索树 - 对于n个项目的地图,我们只需要将每个令牌与log n不同的键进行比较。
如果没有对你的问题进行任何进一步限制,我怀疑你是否能获得更高效率 - m令牌的最坏情况复杂度O(m log n)和n个键值对的映射。 / p>
这很不错,但并不令人敬畏;如此重要的问题:您有什么方法可以利用您的数据吗?
答案 1 :(得分:1)
如果您使用Aho-Corasick string matching algorithm,则可以在不必将文本拆分为标记的情况下执行此操作。只需让叶子节点上的输出状态返回替换字符串。
这可能比将文本拆分为标记更快,因为您不必管理字符串。它逐个字符。比使用哈希表查找快多少是你必须要测试的东西。与简单的哈希表查找相比,这也有点难以实现。
答案 2 :(得分:0)
我猜你实际上是在寻找一种更高级语言的有效解决方案(node.js?python?);一般来说,如果您使用这种语言,建议您使用该语言本机支持的数据结构,这将是Python中的字典和Javascript中的对象。你可能已经知道了。
如果您是用较低级别的语言编写的,那么您可能希望选择一个不会为每个单词不必要地构造字符串对象的优化,假设绝大多数单词不受替换的影响。一种方法是使用逐个字符的散列算法,并在读取输入字符时进行计算,每次启动新单词时重置。当您到达单词的末尾时,如果某个目标具有该哈希值,则可以检查平均O(1)
时间。如果没有,请继续阅读。您可以定期将输入缓冲区刷新到输出,只要保留当前字。
如果目标很长(可能不是这种情况),你通常可以通过存储目标字符串的前缀(或一些前缀)的哈希值来避免必须保留当前单词。然后,当您的输入缓冲区耗尽时,您可以检查当前哈希值是否与适当长度的前缀之一的哈希值匹配。偶尔检查一下这个表单也可以解决基于故意创建哈希冲突的DoS攻击(虽然在你的情况下,这不是一个问题;攻击者可以做的就是强迫你对每个单词进行全文比较;他们无法将自己的单词添加到哈希表中。)
但是,如果我用C语言等低级语言编写这段代码,我可能会将目标词放入trie中,并在每个输入字符上跟踪trie。一旦trie中没有匹配项,您就可以刷新到当前单词的结尾;很可能在所有不匹配的单词中很早就会发生,甚至可能在他们的第一个角色上发生。虽然trie通常需要比哈希映射更多的存储空间(甚至可能需要多于BST),但存在压缩技术(如果可以提前设置数据结构),并且提前停止检查单词的能力可能是取胜。
答案 3 :(得分:0)
其他人提到了二进制搜索和哈希映射。我怀疑有一种稍微快一点的方法,因为你不关心内存使用效率。 Bucket会对您要查找的数据进行排序并与之进行比较。这样可以加快比较速度 - 而不是对完整输入进行哈希处理然后匹配,它总是在寻找完全匹配。
鉴于地图{ABC, ABD, DEF, GH}
您的数据结构看起来像......
pos: 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 <-- slot 26 is reserved for
val: A 0 0 D 0 0 G 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "end of map token"
| | |
B E H <-- sub buckets don't show all buckets as in the top level, but they
/ \ | | are all there.
C D F END
/ | \
END END END
扩展您正在接受的完整字符集,或每个字节255个可能的值。然后,当您获得输入时,您可以测试每个角色。
例1:
Input: ABC
1: look up location 'Z' - 'A' = 0
2: is there anything in this bucket? yes
3: look in sub-buckets.
4: Is there anything in the 'Z'- 'B' bucket? yes
5: look in sub buckets.
6: Is there anything in the 'Z' - 'C' bucket? yes
7: look in sub-buckets
8: reached end of input token. Is end of map bucket is marked? yes
9: match found
例2:
Input: ABCD (input token longer than closest match in map)
1: look up location 'Z' - 'A' = 0
2: is there anything in this bucket? yes
3: look in sub-buckets.
4: Is there anything in the 'Z'- 'B' bucket? yes
5: look in sub buckets.
6: Is there anything in the 'Z' - 'C' bucket? yes
7: look in sub-buckets
8: Is there anything in the 'Z' - 'D' bucket? no
9: match not found
例3:
Input: ABE
1: look up location 'Z' - 'A' = 0
2: is there anything in this bucket? yes
3: look in sub-buckets.
4: Is there anything in the 'Z'- 'B' bucket? yes
5: look in sub buckets.
6: Is there anything in the 'Z' - 'E' bucket? no
7: match found