C++ 回文自动机(PAM):原理、实现与应用
回文自动机(Palindrome Automaton, PAM,也叫回文树)是专门处理字符串回文子串问题的高效数据结构,由 Mikhail Rubinchik 在 2015 年提出。它能在 O(n) 时间复杂度内构建,支持统计回文子串数量、查找最长回文子串、统计各长度回文子串出现次数等核心问题,是处理回文问题的'专属利器'。本文将从核心原理、节点设计、构建流程到实战应用,全面解析回文自动机的设计思想与 C++ 实现技巧。
一、回文自动机的核心背景与优势
1.1 问题引入:回文子串处理的瓶颈
传统处理回文子串的方法(如中心扩展法 O(n^2)、Manacher 算法 O(n))存在明显局限:
- 中心扩展法:时间复杂度高,无法高效统计所有回文子串的出现次数;
- Manacher 算法:仅能找到最长回文子串,无法统计所有回文子串的信息;
- 后缀自动机/后缀数组:需额外处理回文特性,针对性差。
回文自动机的核心价值:
- 线性时间构建:仅需一次遍历字符串,时间复杂度 O(n);
- 精准适配回文:专为回文子串设计,可直接统计所有回文子串的数量、出现次数;
- 空间高效:节点数等于字符串中不同回文子串的数量(最多 n 个),空间复杂度 O(n)。
1.2 核心概念定义
回文自动机的设计基于回文的核心性质:一个长度大于 2 的回文子串,其去掉首尾字符后仍是回文子串。核心定义如下:
- 节点:每个节点唯一对应一个本质不同的回文子串(如 'a' 和 'aa' 是不同节点);
- 长度(len):节点对应回文子串的长度;
- 失败指针(fail):类似 AC 自动机的失败指针,指向当前节点对应回文子串的最长后缀回文子串对应的节点;
- 转移(trans):
trans[u][c] = v表示在节点 u 对应回文子串的首尾添加字符 c 后,得到节点 v 对应的回文子串; - 两种初始节点:
- 偶根(0 号节点):对应空串,长度 len=0;
- 奇根(1 号节点):对应虚拟回文子串(辅助处理奇数长度回文),长度 len=-1;
- last 指针:指向当前字符串最后一个字符结尾的最长回文子串对应的节点(核心优化,避免重复查找)。
示例:字符串 s = "abba" 的回文自动机结构:
偶根(0,len=0,fail=-1) ├─ fail → 奇根(1,len=-1,fail=-1) ├─ trans['a'] → 节点 2(len=1,"a",fail=1) │ └─ trans['b'] → 节点 3(len=3,"aba",fail=2)(若有) └─ trans['b'] → 节点 4(len=1,"b",fail=1) └─ trans['b'] → 节点 5(len=2,"bb",fail=0) └─ trans['a'] → 节点 6(len=4,"abba",fail=2)
二、回文自动机的核心结构设计
2.1 节点与全局变量定义
回文自动机的核心是节点结构和全局状态管理,C++ 实现如下:
#include <iostream>
#include <vector>
#include
std;
{
trans[];
fail;
len;
cnt;
() {
(trans, , (trans));
fail = ;
len = ;
cnt = ;
}
};
vector<PAMNode> pam;
string s;
last;
size;


