模拟搜索算法

这是我的问题:

在给定的文档(字符串)中,例如:

"hello there my name is dominic and my name is very special"

和searchTerm(列表),例如:

['my','dominic'] or ['dominic','my'] (shouldn't matter)

算法将返回包含以下内容的文档的最短摘录:

>>> 'dominic and my'

因为

>>> 'my name is dominic'

比以前包含更多的单词。

这是我目前的想法:

通过创建一个内部列表元素数量等于搜索词数量的列表来开始算法。在每个列表的内部将是索引,该搜索元素将出现在文档中。

document = document.split();

所以searchTerms = ['my', 'dominic']会回来

[[2,7], [5]]

因为my出现在索引处2,7并且dominic仅出现在5。

然后,算法将获取此列表并生成所有可能性的列表:

[[2,5], [7,5]]

如您所见,文档字符串中有两个子字符串,其中包含my和dominic。然后,算法可以采用我做的两个内部列表的范围。max()-min()这将告诉我文档的第二个摘录小于第一个摘录,然后return document[5:(7+1)]可能是预期的结果。

就我的想法而言,这就是我到目前为止所拥有的:

document = "hello there my name is dominic and my name is very special"

searchTerms = ['my', 'dominic']

def answer(document, searchTerms):

index = []

document = document.split()

for a in range(0, len(searchTerms)):

index.append([i for i, x in enumerate(document) if x == searchTerms[a]])

return index

到目前为止,这[[2,7],[5]]仍然是我遇到的一个主要问题:

-效率:

此解决方案对于极大的文档字符串和搜索词列表是否有效?如果不能,那么可以做些什么来提高效率,或者我的初衷不是很好

感谢您对解决此问题的任何见解,谢谢。

解决方案

您的算法在平庸的输入上的执行速度可能会非常慢。假设您有10个搜索词和包含10000个单词的文本。在这种情况下,可能每个术语都有1000个索引的列表。最终将产生1000 ^ 10的总可能性。

就大O表示法而言,复杂度为O((n / k)^ k),其中n是文本中的术语数,k-搜索项的数量。

这是想法更快的算法。在逐个单词地迭代文档时,我们需要跟踪最接近当前位置的搜索词索引。我们称其为结构查询(简单的python字典)。快速示例:

"hello there my name is dominic and >my< name is very special"

假设我们要访问突出显示的“我的”单词。此时,查询为{“ my”:2,“ dominic”:5}。当前的“我的”将更接近文本中的任何其他单词。因此,当访问下一个单词(“名称”)时,我们将更新版本{{my“:7,” dominic“:5}。显而易见,最佳解决方案与查找状态之一相对应。因此,要获得答案,只需跟踪字典中的max()-min()值即可。注意:只有当所有搜索词都作为查找关键字出现时,您才应该开始跟踪。

在每次出现搜索词时,我们都需要从位置查找中迭代k个值,因此该算法的复杂度为O(nk)。

为了使它更好,您还可以将平衡BST与来自查找的索引一起使用。现在,除了可以迭代查找值(O(k))之外,您还可以在O(logk)中检索最小索引:

min_index = bst.min()

old_index=lookup[curr_term] # O(1)

bst.delete(old_index) # O(logk)

bst.insert(new_index) # O(logk)

在这种情况下,总复杂度将为O(nlogk)。

编辑。没有树优化的代码(在Python中找不到内置的BST):

document = "hello there my name is dominic and my name is very special"
searchTerms = { 'my', 'dominic' } # set has faster lookups
doc_words = document.split()
from sys import maxint
def search(words, terms):
found_terms = [[i,x] for i,x in enumerate(words) if x in terms]
lookup = {}
cnt = maxint
k = len(terms)
start,end=-1,-1
for i,w in found_terms:
lookup[w] = i
if k == len(lookup):
min_idx = min(lookup.values())
curr = i - min_idx
if curr < cnt:
cnt,start,end = curr,min_idx,i
return words[start:end + 1]