是否可以在 O(n) 中计算字符串中不同子串的数量?

Is it possible to count the number of distinct substrings in a string in O(n)?

给定一个长度为 n 的字符串 s,是否可以在 O(n) 中计算 s 中不同子串的数量?

例子

输入:abb

输出:5 ('abb', 'ab', 'bb', 'a', 'b')

我做了一些研究,但我似乎无法找到一种算法来如此有效地解决这个问题。我知道 O(n^2) 方法是可能的,但是有更有效的算法吗?

我不需要获取每个子字符串,只需要获取不同子字符串的总数(以防有所不同)。

构造LCP array并从子串数(n(n+1)/2)中减去它的和。

您可以使用 Ukkonen 算法在线性时间内构建后缀树:

https://en.wikipedia.org/wiki/Ukkonen%27s_algorithm

那么s的子串个数就是trie中字符串的前缀个数,线性时间简单计算即可。它只是所有节点中的字符总数。

例如,您的示例生成的后缀树如下:

            /\                
           b  a
           |  b
           b  b

树中有 5 个字符,所以有 5 个子字符串。每个唯一的字符串都是从根开始的路径,以不同的字母结尾:abb、ab、a、bb、b。所以字符串的个数就是树中字母的个数。

更准确地说:

  • 每个子串都是字符串的某个后缀的前缀;
  • 所有后缀都在trie中;
  • 所以通过trie的子串和路径是一一对应的(根据trie的定义);和
  • 树中的字母与non-empty路径是一一对应的,因为:
    • 每个不同的 non-empty 路径在其最后一个字母之后的不同位置结束;和
    • 每个字母后面位置的路径是唯一的

对于想知道如何在 O(N) 时间内构建包含 O(N^2) 个字符的树的人们请注意:

后缀树的表示有一个技巧。不是将实际字符串存储在树的节点中,而是将指针存储到原始字符串中,因此包含 "abb" 的节点没有 "abb",它具有 (0,3) - - 每个节点2个整数,不管每个节点中的字符串有多长,后缀树有O(N)个节点。