我试图弄清楚如何在后缀数组中出现二进制搜索一次出现模式。
我们有一个文字:petertomasjohnerrnoerror
。
我试着找er
。
SA
是此文字的后缀数组:8,14,19,3,1,12,10,7,13,17,18,11,6,22,0,23,16,21,15,20,4,9,2,5
现在,我想找到后缀数组的任何索引,该值指向一个'er'
。因此输出将是SA中的索引,指向3,14 or 19
,因此它将返回1,2或3
我试图使用二进制搜索,但我无法弄清楚如何。
def findOneOccurence(text,SA,p):
high = len(text)-1 # The last index
low = 0 # the lowest index
while True:
check = (high-low)/2 # find a middle
if p in text[SA[check]:SA[check]+len(p)]:
return check
else:
if text[SA[check]:SA[check]+len(p)]<p:
low = check
else:
high = check
if high<=low:
return None
返回11
。但是text[SA[11]:SA[11]+2]
是'oh'
的{{1}}个instad。
哪个可能是问题?
此功能适用于有关数百万个字符的大量文本。
编辑:我发现了一个错误。而不是'er'
应该是text[SA[check]:SA[check+len(p)]]<p:
,而是它仍然是错误的。它返回None而不是text[SA[check]:SA[check]+len(p)]<p:
编辑II:另一个错误:如果高&gt; =低变为高&lt; =低,现在,它返回2,这是好的。
编辑III:现在它可以工作,但是在某些输入上它会进入循环并且永远不会结束。
答案 0 :(得分:2)
借阅和编辑https://hg.python.org/cpython/file/2.7/Lib/bisect.py
>>> text= 'petertomasjohnerrnoerror'
>>> SA = 8,14,19,3,1,12,10,7,13,17,18,11,6,22,0,23,16,21,15,20,4,9,2,5
>>> def bisect_left(a, x, text, lo=0, hi=None):
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if text[a[mid]:] < x: lo = mid+1
else: hi = mid
if not text[a[lo]:].startswith(x):
# i suppose text[a[lo]:a[lo]+len(x)] == x could be a faster check
raise IndexError('not found')
return a[lo]
>>> bisect_left(SA, 'er', text)
14