Z函数
也就是,它想找前缀和以s[i]开头的后缀的LCP
思想
维护一个右端点最右的z-box
结合z[i - l]的结果和朴素算法进行优化
Z函数Python模版
def sumScores(self, s: str) -> int:n = len(s)z = [0] * nl = r = 0 # 右端点最右的z-boxfor i in range(1, n):if i <= r: # 沿用之前的结果z[i] = min(z[i - l], r - i + 1)while i + z[i] < n and s[z[i]] == s[i + z[i]]: # 朴素写法l, r = i, i + z[i]z[i] += 1return z
例题1
这道题希望找到z函数中满足i为k的倍数,且z[i]可以完全匹配完从i开始的后缀的最小值
class Solution:def minimumTimeToInitialState(self, s: str, k: int) -> int:n = len(s)z = [0] * nl = r = 0 # 右端点最右的z-boxfor i in range(1, n):if i <= r: # 沿用之前的结果z[i] = min(z[i - l], r - i + 1)while i + z[i] < n and s[z[i]] == s[i + z[i]]: # 朴素写法l, r = i, i + z[i]z[i] += 1if i % k == 0 and z[i] == n - i: # 前缀和后缀完全匹配return i // kreturn int(ceil(n / k))
例题2
这道题求z函数之和,由于z函数不包括原字符串,所以要加上原字符串长度
class Solution:def sumScores(self, s: str) -> int:n = len(s)z = [0] * nl = r = 0 # 右端点最右的z-boxfor i in range(1, n):if i <= r: # 沿用之前的结果z[i] = min(z[i - l], r - i + 1)while i + z[i] < n and s[z[i]] == s[i + z[i]]: # 朴素写法l, r = i, i + z[i]z[i] += 1return sum(z) + len(s)
总结
Z函数:对于字符串s,找 s前缀 和 以s[i]开头的后缀 的LCP(最长公共前缀),用到了DP的思想(借用前面的结果)
参考文献
oi-wiki
z函数知乎高赞回答