manacher

马拉车算法是用来处理回文字符串的(其实可以用后缀数组但是后缀数组是nlogn的),其是一种非常的高效的简单算法

首先我们考虑一些暴力做法,考虑枚举位置i,然后对于任意一个i都向两边扩展,然后你就得到了一个n^2的假算。考虑有两个问题,一是你会发现对于偶数的串,会wa比如zqxxqz

其为1 1 1 1 1 1 然后就wa了,另一个问题是它是n^2的。

对于第一个问题我们在每个字符之间插入一个奇怪的字符,这样所有的串都会变成奇数串比如 %z%q%x%x%q%z%

对于第二个问题我们就要进行一些优化了,考虑如何利用上之前的求出的内容,我们考虑维护一个数组len[i]表示:对于一个以i为中心的回文串的右边的字符个数。

然后我们就会发现一个很显然的性质,以i为中心的原串的回文串长度=len[i]-1。(因为你往里面放了新的那个奇怪的字符)

然后我们就可以考虑如何求出len[i],考虑从左到右处理len[i]

考虑维护一个r一个mid,表示之前的所有len中右端点最远的r ,其对应的中心mid。

然后我们来进行分类讨论

若r>=i那么我们可以发现i被之前的回文串所覆盖了,那么它一定能得到其对称的那个串的长度但是要对于r-i取min(因为右边还没有被匹配)

若r<i那么我们可以发现他不可能用上之前的,所以他是1

然后我们开始往右扩展(就和暴力一样)

然后更新r和mid

浅浅的证明一下时间复杂度,我们会发现对于每一个位置他会由之前的扩展到或者有自己扩展,但不论被哪种方式扩展都只会被扩展一次,所以你就能够发现他是O(n)的

然后你就学会了这个简单的算法

然后发一下我写的很拉的代码

复制代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
namespace lin
{
    char s[11000100];
    char t[22000100];
    int len[22000100];
    int love(int wjl)
    {
        scanf("%s",s+1);
        int n=strlen(s+1);
        int cnt=0;
        t[cnt]='&';
        for(int i=1;i<=n;i++)
        {        
            t[++cnt]='#';
            t[++cnt]=s[i];                        
        }
        t[++cnt]='#';
        t[++cnt]='@';
        int mid=0,r=0,ans=0;
        for(int i=1;i<cnt;i++)
        {
            len[i]=min(r-i,len[mid*2-i]);
            len[i]=max(len[i],1);
            while(t[i+len[i]]==t[i-len[i]]) len[i]++;
            if(i+len[i]>r)
            {
                r=i+len[i];
                mid=i;
            }
            ans=max(len[i],ans);
        }
        printf("%d",ans-1);
        return wjl;
    }
}
int main()
{
    return lin::love(0);
}
复制代码

 

posted @   lntyh  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示