我必须实现Z算法并使用它来搜索特定模式的目标文本。我已经实现了我认为正确的算法和使用它的搜索功能,但它真的很慢。对于字符串搜索的天真实现,我一直有低于1.5秒的时间,对于z字符串搜索,我一直有超过3秒的时间(对于我最大的测试用例)所以我必须做错事。结果似乎是正确的,或者至少是我们给出的少数测试案例。我的咆哮中提到的功能的代码如下:
import sys
import time
# z algorithm a.k.a. the fundemental preprocessing algorithm
def z(P, start=1, max_box_size=sys.maxsize):
n = len(P)
boxes = [0] * n
l = -1
r = -1
for k in range(start, n):
if k > r:
i = 0
while k + i < n and P[i] == P[k + i] and i < max_box_size:
i += 1
boxes[k] = i
if i:
l = k
r = k + i - 1
else:
kp = k - l
Z_kp = boxes[kp]
if Z_kp < r - k + 1:
boxes[k] = Z_kp
else:
i = r + 1
while i < n and P[i] == P[i - k] and i - k < max_box_size:
i += 1
boxes[k] = i - k
l = k
r = i - 1
return boxes
# a simple string search
def naive_string_search(P, T):
m = len(T)
n = len(P)
indices = []
for i in range(m - n + 1):
if P == T[i: i + n]:
indices.append(i)
return indices
# string search using the z algorithm.
# The pattern you're searching for is simply prepended to the target text
# and than the z algorithm is run on that concatenation
def z_string_search(P, T):
PT = P + T
n = len(P)
boxes = z(PT, start=n, max_box_size=n)
return list(map(lambda x: x[0]-n, filter(lambda x: x[1] >= n, enumerate(boxes))))
答案 0 :(得分:2)
您对z-function def z(..)
的实现在算法上是正确的,并且渐近正常。
在最坏的情况下,它具有O(m + n)时间复杂度,而在最坏的情况下,天真字符串搜索的实现具有O(m * n)时间复杂度,因此我认为问题出在您的测试用例中。
例如,如果我们采用这个测试用例:
T = ['a'] * 1000000
P = ['a'] * 1000
我们将获得z-function:
real 0m0.650s
user 0m0.606s
sys 0m0.036s
和天真的字符串匹配:
real 0m8.235s
user 0m8.071s
sys 0m0.085s
PS:你应该明白,有很多测试用例,其中天真的字符串匹配也在线性时间内工作,例如:
T = ['a'] * 1000000
P = ['a'] * 1000000
因此,天真字符串匹配的最坏情况是函数应该应用模式并反复检查。但在这种情况下,由于输入的长度,它只会进行一次检查(它不能应用索引1的模式,因此它不会继续)。