字符串算法小结

KMP

字符串单模匹配算法。

\(S\)是模板串,\(T\)是文本串,\(next(i)\)表示字符串\(T[1...i]\)的所有后缀中还是\(T\)的前缀的最长的长度,失配时利用\(next(i)\)转移即可。

时间复杂度为均摊\(O(|S|+|T|)\)

Manacher

求一个字符串的所有回文子串。

\(maxright\)为目前处理的所有回文串的最大右端点,如果当前处理的中心\(i \leq maxright\),则可以利用之前的信息加速。

时间复杂度为均摊\(O(|S|)\)

哈希

好像没什么可说的。

Trie树

好像没什么可说的。

时间复杂度为\(O(\sum |S|)\)

AC自动机

字符串多模匹配算法。

\(fail(x)\)指针指向\(x\)所代表的字符串的所有后缀中最长的是一个模板串的前缀的那个前缀,与\(KMP\)类似,失配时利用\(fail(x)\)转移。

一些值得注意的性质:

  1. \(Trie\)树上一个节点的祖先是这个字符串的前缀。

  2. \(fail\)树上一个节点的祖先是这个字符串的后缀。

[NOI2011]阿狸的打字机

子串就是前缀的后缀,所以只需统计从根到长串的结束节点的路径上的所有节点有几个在\(fail\)树上短串的结束节点的子树内即可。

后缀数组

将所有后缀按字典序排序。

\(sa[i]\)表示第一关键字排名为\(i\)的后缀。

\(rk[i]\)表示后缀\(i\)的排名。

\(sc[i]\)表示第二关键字排名为\(i\)的后缀。

算法就是用\(rk_{wd}\)\(sc_{wd}\)推出\(sa_{wd}\),再用\(sa_{wd}\)\(rk_{wd}\)推出\(rk_{2wd}\),用\(sa_{wd}\)推出\(sc_{2wd}\)

时间复杂度为\(O(|S| \log |S|)\)

\(height[i]\)表示排名为\(i-1\)的后缀和排名为\(i\)的后缀的\(LCP\),可以通过性质\(height[rk[i-1]]-1 \leq height[rk[i]]\)在均摊\(O(|S|)\)的时间复杂度内求出。

时常搭配\(ST\)表或并查集或单调栈或笛卡尔树或启发式合并等算法食用。

后缀自动机

构造方法太麻烦就不说了,时间复杂度为\(O(|S| \varsigma)\)

后缀自动机存储了一个字符串的所有子串,把\(right\)集合相同的子串存储在同一个结点上。

\(Parent\)树上一个节点的祖先是这个字符串的后缀,维护\(right\)集合的方法是\(Parent\)树上线段树合并或启发式合并。

反串的\(Parent\)树是这个字符串的后缀树。

[CF666E]Forensic Examination

\(T\)建广义后缀自动机,\(Parent\)树上线段树合并维护\(right\)集合,倍增找\(S[p_l...p_r]\)\(T\)\(Parent\)树上对应的节点。

Shift-And

字符串单模匹配算法。

预处理出每个字符在模板串中出现位置的集合,用\(bitset\)维护。匹配的同时用一个\(bitset\)维护当前可以匹配到模板串的哪些位置,通过\(bitset\)之间的快速运算可以加速转移。

当字符串中存在通配符时非常好用。

时间复杂度为\(O(\frac{|S| \times |T|}{\omega})\)

posted on 2019-06-25 18:17 ErkkiErkko 阅读(...) 评论(...) 编辑 收藏

统计