Manacher马拉车

Manacher

Manacher算法是一种用于查找字符串中最长回文子串的线性时间复杂度算法。

算法原理

Manacher算法的核心思想是利用回文串的对称性来避免重复计算。它通过维护一个"最右回文边界"和对应的中心点,来高效地扩展回文半径。

算法步骤

1. 预处理扩展字符串

为了转化偶数长度的回文串为奇数长度的回文串,我们在字符串中的每个字符中间插入一个不会有的字符(如‘|’‘&’),然后再在字符串前插入一个奇奇怪怪没有用过的字符。

代码如下:

//读入原字符串str
data[0]='~',data[1]='|';
for(int i=0; i<str.size(); i++)
{
    data[++cnt]=str[i],data[++cnt]='|';
}
//data即为扩展字符串

2. 线性处理回文半径

记一个最右的回文串右端点 rrr 即其对应的回文中心 ccc,然后分四种情况处理(为方便表示,记以 ccc 为回文中心的回文串为 strcstr_cstrc):

  1. 若当前 ttt 超过了 111i−1i-1i1 最大的回文串的范围,则暴力扩展求 PtP_tPt
  2. 若没超过,且 ttt 的关于 ccc 的对称点 2c−t2c-t2ct 所对应的回文串 str2×c−tstr_{2×c-t}str2×ct 包含在 strcstr_cstrc 内,则直接令 Pt=P2×c−tP_t=P_{2×c-t}Pt=P2×ct
  3. ttt 的对应点所对应的回文串部分超出 strcstr_{c}strc,则令 Pt=r−t+1P_t=r-t+1Pt=rt+1
  4. str2×c−tstr_{2×c-t}str2×ct 压在 strcstr_cstrc 的边界上,则让 Pt=2×c−tP_t=2×c-tPt=2×ct 后暴力继续扩展

为了方便,在具体实现中,我把四种情况并起来写。

代码如下:

for(long long t=1,r=0,mid=0; t<=cnt; t++)
{
    if(t<=r) p[t]=min(p[(mid<<1)-t],r-t+1);
    while(data[t-p[t]]==data[t+p[t]]) ++p[t];
    if(p[t]+t>r) r=p[t]+t-1,mid=t;
}

3.映射关系

找规律发现,Pt−1P_t-1Pt1 即为以 ttt 为回文中心的最长回文串的长度(注意 PtP_tPt 映射的是扩展串的第 ttt 位)

模板题代码实现

#include<bits/stdc++.h>
using namespace std;
const long long maxn=11000005;
char data[maxn<<1];
long long p[maxn<<1],cnt=1,ans;
string str;
int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>str;
    data[0]='~',data[1]='|';
    for(int i=0; i<str.size(); i++)
    {
    	data[++cnt]=str[i],data[++cnt]='|';
	}
    for(long long t=1,r=0,mid=0; t<=cnt; t++)
    {
        if(t<=r) p[t]=min(p[(mid<<1)-t],r-t+1);
        while(data[t-p[t]]==data[t+p[t]]) ++p[t];
        if(p[t]+t>r) r=p[t]+t-1,mid=t;
        if(p[t]>ans) ans=p[t];
    }
    cout<<ans-1;
	
	return 0;
}

复杂度证明

或许某些大佬看到上面的代码后会想到 O(n)O(n)O(n)O(n2)O(n^2)O(n2) 的均摊,但是实际上不是的:rrr 是一直向右运行的,而 rrr 最多能够运行到 nnn,所以整体的时间复杂度应为 O(n)O(n)O(n).

:本文为编者手搓,如有笔误敬请指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值