Z 函数和独特的子串:破烂的算法随处可见?

Z-Function and unique substrings: broken algorithm parroted everywhere?

我不是一个超级数学迷,所以我可能很容易遗漏一些东西,但让我们从 https://cp-algorithms.com/string/z-function.html 中获取算法并尝试将其应用于字符串 baz。这个字符串肯定有子串集'b','a','z','ba','az','baz'.

让我们看看 z 函数是如何工作的(至少我是如何理解它的):

  1. 我们取一个空字符串并向其添加 'b'。根据算法 z[0] = 0 的定义,因为它未定义大小 1;
  2. 我们取 'b' 并向其添加 'a',反转字符串,我们有 'ab'... 现在我们计算 z 函数... 它产生 {0 , 0}。第一个元素是预期的“未定义”,第二个元素应定义为:

i-th element is equal to the greatest number of characters starting from the position i that coincide with the first characters of s.

所以,在 i = 1 处,我们有 'b',我们的字符串以 a 开头,'b' 与 'a' 不一致,所以当然是 z[i=1]= 0。这将在整个单词中重复。最后,我们留下了全零的 z 数组,尽管该字符串有 6 个子字符串,但它什么也没告诉我们。

我错过了什么吗?有大量网站推荐 count of distinct substrings 的 z 函数,但它...不起作用?我在这里误解了 distinct 的意思吗?

查看测试用例:https://pastebin.com/mFDrSvtm

当你在字符串S[=44=的开头添加一个字符x时,S[的所有子串 仍然是 xS 的子串,但是你得到了多少 new 子串?

  • 新的子串都是xS的前缀。这些有长度(xS),但是
  • 其中
  • max(Z(xS))已经是S的子串,所以
  • 你得到长度(xS) - max(Z(xS)) 新的

因此,给定一个字符串 S,只需将所有长度 (P) - max(Z(P)) 相加即可S.

的每个后缀 P

您的测试用例 baz 有 3 个后缀:zazbaz。所有字母都是不同的,因此它们的 Z 函数处处为零。结果是不同子串的数量正好是后缀长度的总和:3 + 2 + 1 = 6.

尝试baa:Z函数中唯一的non-zero是Z('aa')[1] = 1,所以唯一子串的个数是3 + 2 - 1 + 1 = 5.

请注意,您链接到的文章提到这是一个 O(n2) 算法。这是正确的,尽管它的开销很低。通过构建后缀树可以在 O(n) 时间内完成此操作,但这相当复杂。