家庭作业:在python中实现Z算法,它真的很慢,比天真的字符串搜索慢

时间:2015-09-13 11:45:43

标签: python algorithm string-matching

我必须实现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))))

1 个答案:

答案 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的模式,因此它不会继续)。