【问题标题】:Find all occurrences using binary search in a suffix array在后缀数组中使用二进制搜索查找所有出现
【发布时间】:2018-03-26 21:20:58
【问题描述】:

我想知道是否有一种实现的方法来获取给定子字符串和后缀数组的所有出现。我正在测试我在这里找到的一个函数:https://hg.python.org/cpython/file/2.7/Lib/bisect.py,其中进行了一些修改。我得到的只是发生的位置之一,而还有其他的。例如,

seq = "ATGTGCAAGAATGAGGCAAG$" #original string
array = [20, 17, 6, 9, 18, 7, 13, 10, 0, 16, 5, 19, 8, 12, 15, 4, 14, 2, 11, 3, 1] #suffix array
def bisect_left(array, query, seq, lo=0, hi=None):
    if lo < 0:
        raise ValueError('must be non-negative')
    if hi is None: #by default len(array)
        hi = len(array)
    while lo < hi: 
        mid = (lo+hi)//2 #set the middle to binary search
        if seq[array[mid]:] < query:
            lo = mid+1
        else:
            hi = mid
    if not seq[array[lo]:array[lo]+len(query)] == query:
        raise IndexError('there is not any index for the query')
    return array[lo]
print(bisect_left(array, 'ATG', seq))

通过执行此操作,输出为10,而应为0,10 有什么问题?

【问题讨论】:

  • 你的输出怎么样?我的列表索引超出范围。
  • 首先,你为什么要修改stdlib bisect_left 函数?您的修改打算做什么?在不知情的情况下很难调试您的更改。
  • 第二,bisect 的全部意义,以及一般的二分搜索,是您可以使用它来搜索已排序的序列。但是您的列表未排序。那么你认为二等分会有什么帮助呢?
  • 另外,我在任何地方都看不到后缀数组或类似的东西,尽管您的标签和您在文本中提及。分子遗传学对于这个术语的含义是否与此处相关的计算机科学有不同的含义?
  • 你反对[m.start() for m in re.finditer('ATG', 'ATGTGCAAGAATGAGGCAAG$')] 输出是[0,10]

标签: python find-occurrences suffix-array


【解决方案1】:

问题是您的搜索方法只返回一个匹配项,而可能有多个匹配项。为了抓住所有这些,我可以想到两个选择:

  1. 首先找到一个匹配项。然后从该点向上和向下移动后缀数组以查找任何其他匹配项。如果匹配的数量不是太大,那么这个解决方案应该足够了,但是如果匹配的数量非常多,它可能会很慢。
  2. 如果您期望有大量匹配项,更好的策略是执行两次二分搜索。第一次二分查找应在后缀数组中查找最左侧的匹配项,第二次查找应查找最右侧的匹配项。

下面我已经实现了其中的第一个。我定义了一个辅助方法 match_at 只是为了避免很多丑陋的嵌套 []s。

seq = "ATGTGCAAGAATGAGGCAAG$" #original string
array = [20, 17, 6, 9, 18, 7, 13, 10, 0, 16, 5, 19, 8, 12, 15, 4, 14, 2, 11, 3, 1] #suffix array

def bisect_left(array, query, seq, lo=0, hi=None):
    if lo < 0:
        raise ValueError('must be non-negative')
    if hi is None: #by default len(array)
        hi = len(array)
    while lo < hi: 
        mid = (lo+hi)//2 #set the middle to binary search
        if seq[array[mid]:] < query:
            lo = mid+1
        else:
            hi = mid

    def match_at(i):
        return seq[i: i + len(query)] == query

    if not match_at(array[lo]):
        raise IndexError('there is not any index for the query')

    # array[lo] is one match
    # now we walk backwards to find the first match
    first = lo
    while first > 0 and match_at(array[first - 1]):
        first -= 1

    # and walk forwards to find the last match
    last = lo
    while match_at(array[last]):
        last += 1

    return array[first:last]

print(bisect_left(array, 'ATG', seq))

【讨论】:

    猜你喜欢
    • 2019-07-15
    • 1970-01-01
    • 2016-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    • 2011-12-09
    相关资源
    最近更新 更多