面试题[hash_map、字典树与倒排索引]: 全文检索

来源:互联网 发布:而知也无涯成语 编辑:程序博客网 时间:2024/05/16 18:34

原始题目

给定一篇英文文献,然后查某个单词在这篇文章中出现了多少次(忽略大小写)。注意这个查找会出现很多次,每一次查不同的单词,请问用什么数据结构和算法来实现尽可能快地查找?

这个很容易想到首先对文章进行分词,然后利用hash_map来保存所有的单词和单词出现的次数。

进阶一

如果想要查找某一个字符串在所有单词的后缀中出现了多少次呢?比方说文章包含三个单词:”auto”, “goto”, “get”。那么后缀”to”出现的次数为两次。

这个可以利用字典树来解(字典树的详细介绍可以参看July的博客:http://blog.csdn.net/v_july_v/article/details/6897097)。

首先将文章中所有的单词翻转之后,存入如下字典树,每往下找到一个字符,就将该节点的次数值加一,完成之后便可得到如下图所示的字典树:

这里写图片描述

现在如果要查找某个后缀的话,可将该后缀翻转之后直接遍历该树即可。比方说要查找后缀”to”出现的次数,先翻转得到”ot”,然后从根节点往下找,找到o之后继续找到t,得到次数为2。

由以上可知,查找效率为O(L),L为查找后缀的长度。

进阶二

如果文献中包含中文呢?比方说要查找”我喜欢STL”在文章中出现了几次。

如果包含中文的话,那就不适合用字典树来处理了,因为这棵树会非常庞大,这时候可以考虑用倒排索引了。搜索引擎的倒排索引是词-文档索引,我们这里只有一篇文章,但是我们需要记录下所有词的前后关系,那么我们可以建立词-位置索引,如下图所示,只列举出了我们关心的几个词的位置。

这里写图片描述

以查找”我喜欢STL”为例,遍历”我”出现的所有位置:
当”我”的位置为1时,查找2是否出现在”喜”字的所有位置中,发现不在,说明是一次失败的匹配;
当”我”的位置为10时,发现11、12、13、14、15分别为”喜”、”欢”、”S”、”T”、”L”,说明是一次成功的匹配;
……

遍历完成之后发现只有起始位置10才是成功的匹配。故”我喜欢STL”出现的次数为1。

再来考虑一下我们要用什么数据结构来保存这个倒排索引,”词-位置“毫无疑问利用hash_map来保存,来使得查找词的效率更高;那么位置集合用什么来保存呢?由于位置也需要频繁地查找,那么可以考虑用hash_set来保存位置。

进阶三

如果”我喜欢”和”STL”可以出现任意三个字符都算是成功的匹配呢?

基于上面的思路,成功匹配到”欢”字的位置索引 idx 之后,继续查找 idx+1+3 是否是”S”,并继续后面的匹配。

在上面的例子中,只有起始位置为40的位置是成功的匹配。

进阶四

如果上面不是固定的三个字符,也可以是0~3个字符呢?

那么可以分别找出前半部分”我喜欢”和后半部分”STL”的所有匹配位置,然后判断两者之间的距离是否在满足要求的范围之内即可。

上面的例子中,”我喜欢”的成功匹配位置有10、40、70;”STL”的成功匹配位置有13和46。先对这两个序列排好序(因为hash_set不是排好序的),然后判断这些位置中哪些是合乎要求的。很明显上面的例子中起始位置10和40都是成功的匹配。

1 0
原创粉丝点击