【学习笔记】字符串回文算法
1.【学习笔记】Kruskal 重构树2.【学习笔记】网络流3.【学习笔记】高级数据结构4.【学习笔记】线性基5.【学习笔记】Link Cut Tree6.【学习笔记】字符串后缀算法
7.【学习笔记】字符串回文算法
8.【学习笔记】组合数学9.【学习笔记】多项式 1:基础操作10.【学习笔记】多项式 2:集合幂级数11.【学习笔记】多项式 3:多项式运算12.【学习笔记】Prufer 序列13.【学习笔记】多项式 4:生成函数14.【学习笔记】DP 套 DP15.【学习笔记】图的连通性16.【学习笔记】差分约束17.【学习笔记】长链剖分18.【学习笔记】2-SAT19.【学习笔记】根号算法20.【学习笔记】Primal-Dual 原始对偶算法21.【学习笔记】Bostan-Mori 算法22.【学习笔记】狄利克雷卷积与高级筛法23.【学习笔记】DP 优化 1:基础优化24.【学习笔记】DP 优化 2:动态 DP25.【学习笔记】李超线段树26.【学习笔记】优化建图27.【学习笔记】Segment Tree Beats28.【学习笔记】插头 DP29.【学习笔记】任意模数多项式乘法30.【学习笔记】SG 函数与 SG 定理31.【学习笔记】类欧几里得算法32.【学习笔记】狄利克雷前/后缀和/差分33.【学习笔记】DSU on Tree34.【学习笔记】DP 优化 3:闵可夫斯基和优化 DP35.【学习笔记】笛卡尔树36.【学习笔记】Miller-Rabin 算法37.【学习笔记】DP 优化 4:决策单调性38.【学习笔记】DP 优化 5:wqs 二分优化 DP39.【学习笔记】边分治40.【学习笔记】KMP 相关算法41.【学习笔记】概率生成函数42.【学习笔记】离散对数和剩余Manacher#
非线性的求回文算法#
-
:枚举每个位置作为中心,不断向两侧扩展。
-
:二分+哈希。
线性的求回文算法#
维护一个回文串 为当前右端点最靠右的回文串,设当前枚举位置 , 与 回文中心对称的位置 。
由于 的最长回文半径已经处理过,因此当 时,分别以 和 为中心的回文串中的部分(在 中的部分)同样对称;剩余情况则从 开始。
按照暴力的方法扩展,更新 ,这里由于 只增不减,所以总扩展次数是 的。
回文分奇数偶数两种,统一处理一般插入分隔符。
然而事实上求回文串的的线性算法不会优化算法瓶颈。(对数复杂度中二分与数据结构中的修改是并列的)
点击查看代码
int n;
char s[maxn<<1];
int d[maxn<<1];
int ans;
inline void Manacher(){
for(int i=1,l=0,r=-1;i<=2*n+1;++i){
int j=l+r-i,k;
if(i>r) k=1;
else k=min(d[j],r-i+1);
while(i-k>=1&&i+k<=2*n+1&&s[i-k]==s[i+k]) ++k;
d[i]=k;
ans=max(ans,(d[i]*2-1)/2);
if(i+k-1>r) l=i-k+1,r=i+k-1;
}
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
for(int i=n;i>=1;--i) s[i*2]=s[i];
for(int i=0;i<=n;++i) s[i*2+1]='#';
Manacher();
printf("%d\n",ans);
return 0;
}
回文自动机 Palindrome Automaton#
构建#
与回文有关且同样存在后缀指针的一种自动机。
由于回文串分奇数偶数,自动机存在两个根:奇根 和偶跟 ,需要维护回文串长 和最长回文真后缀指针 。
构建的实际过程比较好理解,在上一个节点的基础上增量,一直跳 指针直到可以前后各扩展一个位置(为了方便计算奇根的长度设为 ),如果已经有对应的转移,无需再修改;如果需要新建节点,就要再处理一下两个指针,按照同样方法就可以。设刚刚找到可以扩展的位置 ,那么再寻找到的 指针位置关于 的最长回文串回文中心对称之后,显然是已经出现过的,也就是不需要再新建节点。
将上述过程扩展,也就是在一个字符串结尾增加一个字符,之后最长的回文后缀可能是新增加的,换言之,一个字符串的本质不同回文子串只有不超过 个。
点击查看代码
char s[maxn];
struct PalindromeAutomaton{
int tot,last;
int ch[maxn][26];
int len[maxn],fail[maxn];
PalindromeAutomaton(){
tot=1,last=1;
len[0]=0,fail[0]=1;
len[1]=-1,fail[1]=1;
}
int get_fail(int u,int pos){
while(s[pos-len[u]-1]!=s[pos]) u=fail[u];
return u;
}
void extend(int pos){
int c=s[pos]-'a';
int u=get_fail(last,pos);
if(!ch[u][c]){
int f=get_fail(fail[u],pos);
++tot;
len[tot]=len[u]+2,fail[tot]=ch[f][c];
ch[u][c]=tot;
}
last=ch[u][c];
}
}PAM;
参考资料#
Manacher#
回文自动机 Palindrome Automaton#
- OI Wiki
作者:SoyTony
出处:https://www.cnblogs.com/SoyTony/p/Learning_Notes_about_String_Palindrome_Algorithms.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
合集:
学习笔记
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效