后缀搜索-Python

后缀搜索-Python,python,string,algorithm,search,Python,String,Algorithm,Search,这里有一个解决问题的方法,提供了一个字符串列表和一个文档来查找包含列表中所有字符串的最短子字符串 因此: document = "many google employees can program because google is a technology company that can program" searchTerms = ['google', 'program', 'can'] 输出应为: "can program because google&q

这里有一个解决问题的方法,提供了一个字符串列表和一个文档来查找包含列表中所有字符串的最短子字符串

因此:

document = "many google employees can program because google is a technology company that can program"
searchTerms = ['google', 'program', 'can']
输出应为:

"can program because google"  # 27 chars
而不是:

"google employees can program"  # 29 chars
"google is a technology company that can program"  # 48 chars
这是我的方法, 将文档拆分为后缀树, 检查每个后缀中的所有字符串 返回最短长度之一

这是我的密码

def snippetSearch(document, searchTerms):
    doc = document.split()
    suffix_array = create_suffix_array(doc)
    current = None
    current_len = sys.maxsize
    for suffix in suffix_array:
        if check_for_terms_in_array(suffix, searchTerms):
            if len(suffix) < current_len:
                current_len = len(suffix)
                current = suffix    

    return ' '.join(map(str, current))


def create_suffix_array(document):
    suffix_array = []
    for i in range(len(document)):
        sub = document[i:]
        suffix_array.append(sub)
    return suffix_array


def check_for_terms_in_array(arr, terms):
    for term in terms:
        if term not in arr:
            return False

    return True
def snippetSearch(文档、搜索术语):
doc=document.split()
后缀数组=创建后缀数组(doc)
电流=无
当前长度=sys.maxsize
对于后缀_数组中的后缀:
如果检查\u数组中的\u术语(后缀、搜索术语):
如果长度(后缀)<当前长度:
当前长度=长度(后缀)
当前=后缀
返回“”。加入(映射(str,当前))
def创建后缀数组(文档):
后缀_数组=[]
对于范围内的i(len(文档)):
sub=文件[i:]
后缀_数组。追加(子)
返回后缀数组
def检查_数组中的_术语(arr,术语):
对于术语:
如果术语不在arr中:
返回错误
返回真值

这是一个在线提交,它没有通过一个测试用例。我不知道测试用例是什么。我的问题是,代码是否有逻辑错误。还有更有效的方法吗。

好吧,暴力是
O(n³)
,为什么不:

from itertools import product

def find_shortest(doc, terms):
    doc = document.split()
    substrings = (
        doc[i:j]
        for i, j in product(range(0, len(doc)), range(0, len(doc)))
        if all(search_term in doc[i:j] for search_term in search_terms)
    )
    shortest = doc
    for candidate in substrings:
        if len(candidate) < len(shortest):
            shortest = candidate
    return shortest.
document = 'many google employees can program can google employees because google is a technology company that writes program'
search_terms = ['google', 'program', 'can']

print find_shortest(document, search_terms)
>>>> ['program', 'can', 'google']
来自itertools导入产品的

def查找(文件、条款):
doc=document.split()
子字符串=(
文件[i:j]
对于产品中的i,j(范围(0,len(doc)),范围(0,len(doc)))
如果全部(搜索条件中搜索条件的文档[i:j]中的搜索条件)
)
最短=doc
对于子字符串中的候选人:
如果len(候选人)>>>['program','can','google']

不过,您可能可以更快地完成此操作。例如,任何相关的子字符串只能以关键字之一结尾。那么,蛮力是
O(n³)
,为什么不:

from itertools import product

def find_shortest(doc, terms):
    doc = document.split()
    substrings = (
        doc[i:j]
        for i, j in product(range(0, len(doc)), range(0, len(doc)))
        if all(search_term in doc[i:j] for search_term in search_terms)
    )
    shortest = doc
    for candidate in substrings:
        if len(candidate) < len(shortest):
            shortest = candidate
    return shortest.
document = 'many google employees can program can google employees because google is a technology company that writes program'
search_terms = ['google', 'program', 'can']

print find_shortest(document, search_terms)
>>>> ['program', 'can', 'google']
来自itertools导入产品的

def查找(文件、条款):
doc=document.split()
子字符串=(
文件[i:j]
对于产品中的i,j(范围(0,len(doc)),范围(0,len(doc)))
如果全部(搜索条件中搜索条件的文档[i:j]中的搜索条件)
)
最短=doc
对于子字符串中的候选人:
如果len(候选人)>>>['program','can','google']

不过,您可能可以更快地完成此操作。例如,任何相关的子字符串只能以关键字之一结尾。您可以将其分为两部分。首先,查找与某些属性匹配的最短子字符串。我们将假设我们已经有了一个测试属性的函数:

def find_shortest_ss(document, some_property):
    # First level of looping gradually increases substring length
    for x in range(len(document)):
        # Second level of looping tests current length at valid positions
        for y in range(max(len(document), len(document)-x)):
            if some_property(document[y:x+y]):
                return document[y:x+y]
    # How to handle the case of no match is undefined
    raise ValueError('No matching value found')
现在,我们要为其自身测试的属性:

def contains_all_terms(terms):
    return (lambda s: all(term in s for term in terms))
lambda
表达式接受一些术语,并将返回一个函数,当对字符串求值时,当且仅当所有术语都在字符串中时,该函数才返回true。这基本上是嵌套函数定义的更简洁版本,您可以这样编写:

def contains_all_terms(terms):
    def string_contains_them(s):
        return all(term in s for term in terms)
    return string_contains_them
所以我们实际上只是返回我们在
包含所有术语的
函数中动态创建的函数的句柄

要将其拼凑在一起,我们需要这样做:

>>> find_shortest_ss(document, contains_all_terms(searchTerms))
'program can google'
此代码具有的一些效率优势:

  • any
    内置函数具有短路求值功能,这意味着一旦找到不包含的子字符串,它将返回
    False

  • 它首先检查所有最短的子字符串,然后继续增加子字符串长度,一次增加一个字符长度。如果它找到一个令人满意的子字符串,它将退出并返回该值。因此,您可以保证返回的值永远不会超过需要的长度。它甚至不会在子字符串上执行超过必要时间的任何操作

  • 8行代码,我认为还不错


  • 你可以把它分成两部分。首先,查找与某些属性匹配的最短子字符串。我们将假设我们已经有了一个测试属性的函数:

    def find_shortest_ss(document, some_property):
        # First level of looping gradually increases substring length
        for x in range(len(document)):
            # Second level of looping tests current length at valid positions
            for y in range(max(len(document), len(document)-x)):
                if some_property(document[y:x+y]):
                    return document[y:x+y]
        # How to handle the case of no match is undefined
        raise ValueError('No matching value found')
    
    现在,我们要为其自身测试的属性:

    def contains_all_terms(terms):
        return (lambda s: all(term in s for term in terms))
    
    lambda
    表达式接受一些术语,并将返回一个函数,当对字符串求值时,当且仅当所有术语都在字符串中时,该函数才返回true。这基本上是嵌套函数定义的更简洁版本,您可以这样编写:

    def contains_all_terms(terms):
        def string_contains_them(s):
            return all(term in s for term in terms)
        return string_contains_them
    
    所以我们实际上只是返回我们在
    包含所有术语的
    函数中动态创建的函数的句柄

    要将其拼凑在一起,我们需要这样做:

    >>> find_shortest_ss(document, contains_all_terms(searchTerms))
    'program can google'
    
    此代码具有的一些效率优势:

  • any
    内置函数具有短路求值功能,这意味着一旦找到不包含的子字符串,它将返回
    False

  • 它首先检查所有最短的子字符串,然后继续增加子字符串长度,一次增加一个字符长度。如果它找到一个令人满意的子字符串,它将退出并返回该值。因此,您可以保证返回的值永远不会超过需要的长度。它甚至不会在子字符串上执行超过必要时间的任何操作

  • 8行代码,我认为还不错


  • 我没有强制执行所有可能的子字符串,而是强制执行所有可能的匹配单词位置。。。应该快一点

    import numpy as np
    from itertools import product
    
    
    document = 'many google employees can program can google employees because google is a technology company that writes program'
    searchTerms = ['google', 'program']
    
    word_lists = []
    
    for word in searchTerms: 
        word_positions = []
        start = 0  #starting index of str.find()
        while 1:
            start = document.find(word, start, -1)
            if start == -1:  #no more instances
                break
            word_positions.append([start, start+len(word)])  #beginning and ending index of search term
            start += 1  #increment starting search postion
        word_lists.append(word_positions)  #add all search term positions to list of all search terms
    
    minLen = len(document)
    lower = 0
    upper = len(document)
    for p in product(*word_lists):  #unpack word_lists into word_positions
        indexes = np.array(p).flatten()  #take all indices into flat list
        lowerI = np.min(indexes)
        upperI = np.max(indexes)
        indexRange = upperI - lowerI  #determine length of substring
        if indexRange < minLen: 
            minLen = indexRange
            lower = lowerI
            upper = upperI
    
    print document[lower:upper]
    
    将numpy导入为np
    来自意大利