模拟搜索算法
这是我的问题:
在给定的文档(字符串)中,例如:
"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]