Manacher(马拉车)算法

1.前置知识

回文子串  回文的子串
最长回文子串  字符串中最长的回文子串
回文半径  设以i为中心的最大回文子串的长度为n,则这个字符串第i位的回文半径为(n+1)/2

2.算法流程

2.1 预处理

在处理回文子串(马拉车算法适用)的问题时,一般需要求出每一位的回文半径
经常做字符串题目的同学都知道,在处理这种问题时,最大的阻碍一般就是字符串长度的奇偶性以及边界
不难想到,我们可以在字符串的首尾分别插入一个字符来解决边界问题
也不难想到,我们可以在每一个字符的首尾都添加一个字符(包括第1个和最后一个)
由此,我们可以得到一个新字符串。
这里举一个例子,
原字符串s:ababa
进行完操作1(首尾标记)的字符串 s1: @ababa@
进行完操作2(字符插入)的字符串 s2: @#a#b#a#b#a#@
根据流程不难得出代码:

cin>>a;//原串
int len=strlen(a);
int k=0;
s[0]='$';
s[1]='#';
k++;
for(int i=0;i<=len;i++)
{
  s[++k]=a[i];
  s[++k]='#';
}
n=k;

是的是的我懂 你们想要照搬 但是看到我那不顺眼的++k急了
这个千万不能改,是先自增在标记!!

2.2 加速盒子(核心部分)

我超,盒!
是的是的学过扩展KMP算法的同学们应该都熟悉的乐子东西
所以接下来就让我演示一下这东西
本质上是一个分类讨论 分三种情况:

2.2.1 在盒内(整体)

如图,

蓝色段全体在盒子内,这个时候直接用对称点的就可以了
举例:

所以这是显而易见的

2.2.2 在盒内(部分)

如图,

蓝色段有一部分出去了,所以从r开始暴力

2.2.3 在盒外(全部)

不配图了,这个是显而易见的,两端都不在盒子内,因此只能暴力求解

2.2.4 更新(upd)

求出d[i]后,如果右端有最大值,那么更新盒位置

2.2.5 代码

依次逻辑则可以写出代码

int manacher(char s[],int n)
{
    d[1]=1;
    for(int i=2,l,r=1;i<=n;i++)
    {
    if(l<=r)
        {
            d[i]=min(d[r-i+l],r-i+1);
        }
    while(s[i-d[i]]==s[i+d[i]])
        {
            d[i]++;
        }
    if(i+d[i]-1>r)
        {
            l=i-d[i]+1;
            r=i+d[i]-1;
        }
    }
}

3.例题

终于学完了
例题可以尝试去做一下A. 【例题1】不交回文串
提示:前缀和+Manacher
这里就不放代码了,自己回家好好思考一下

拜!

posted @   March7thDev  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示