后缀自动机题目汇总
[toc]
01 求一个串的本质不同的子串的个数
1.1 解题思路
在这个字符串上创建SAM,然后统计每个节点代码的字符串的个数。对于节点i
而言,其代表的字符串的个数为其最长长度减去后缀链接指向的节点代表的最长长度。
$$tr[i].len - tr[tr[i].fa].len$$
其实也可以找到所有后缀链接构成的树结构,然后找到入度为零的点,将这些点的len
相加即可。
1.2 时空复杂度
时间复杂度$O(n)$,空间复杂度为$O(n)$,$n$为字符串长度。
1.3 C++代码
1 | /** |
02. 统计第一题中每个不同的子串出现的次数
2.1 解题思路
利用endpos
的定义,直接在后缀树上进行拓扑遍历,同时注意是前缀的状态需要在构造SAM的时候额外加1.
2.2 时空复杂度
时间复杂度$O(n)$,空间复杂度$O(n)$,$n$为字符串长度
2.3 C++代码
1 | /** |
03. 求多个字符串的最长公共子串
3.1 解题思路
我们在其中一个字符串s
上建立SAM,然后依次遍历其它字符串t
,求出t
在s
的每个状态出现的最长子串的长度。同时注意在求完之后,每个节点的信息还需要向其后缀链接的父节点串,因为更长的串也同样包含了它的后缀。
再对每个串的每个状态取一个最小值。处理完所有串之后对所有状态再取一个最大值即可。
3.2 时空复杂度
时间复杂度:假设字符串数量为a
,每个字符串的长度为n
,字符串总长度为m
。
构造SAM$O(n)$
每个字符串在SAM上进行跳转的时候,每次最多前进一次,往后跳的次数不会超过向前跳的次数,所以时间复杂度为$O(n)$。
在每次循环中,需要遍历一下SAM的所有状态,为$O(an)$
所以总的时间复杂度为$O(an)$。
空间复杂度为$O(n)$
3.3 C++代码
1 |
|
04 其它字符串出现在某个字符串的最长前缀
4.1 解题思路
SAM裸题,主串建立SAM,然后其它字符串在SAM上跑即可,直到到了一个不能继续走的地方。
4.2 时空复杂度
主串长度为$n$,要匹配的串的总长度为$m$,
空间复杂度$O(n)$
时间复杂度$O(n + m)$
4.3 C++代码
1 |
|