動機
Z algo
z[i]
是看這個位置i開始,與從0開始的string,有多長是一樣的
所以可以把pattern接到要比對的字串最前面,之後產生z function,去找與pattern一樣長的位置
那重點就是怎麼產生z function?
z function是從i開始往前看,所以可以利用前面已經看過的z[i]
來加速
假設有一個已經生完z[i]
的範圍(最靠右)
- 看i是不是在範圍中,同時看利用之前的
z[i-l]
延伸出去,如果還在範圍,就抄答案 - 不能抄答案就重新算
def mk_z(S):
z = [0]*len(S)
l, r = 0, 1
def extend(l, r):
while r <= len(S) and S[r-l-1] == S[r-1]:
r += 1
return r
# [l,r)
# most examples use [i,r], which is closed range
# I dont like closed range, so I use [l,r) to rewrite this prog
for i in range(1,len(S)):
# ((l) ... i) ..z[i-l].. r
if i < r and i+z[i-l] < r-1: # i+z[i-l] is extended str, and this is in range
z[i] = z[i-l] # so we can compute z[i] directly
else: # i is not in [l,r) or i+z[i-l] >= r-1, so we need a new [l,r)
l = i # new range
r = extend(l, i+1 if i >= r else r) # use new end & extend
z[i] = r-l-1 # new [l,r), new z[i] (compute)
return z
def z_algo(S,pat):
magic = f'{pat}.{S}' # '.' must not exist in S & pat
z = mk_z(magic)
offset = len(pat)+1
for i in range(offset, len(magic)):
if z[i] == len(pat):
return f'found at {i-offset}'
return 'no found'