2020-08-26

小白能懂的Manacher算法从入门到弃坑(马拉车)

马拉车详讲:
1.趣味图片讲解,有助于纯小白理解马拉车原理
可以点我哦QAQ

2.有助于有点基础的小白理解马拉车原理并写出代码
可以点我哦OAO

马拉车刷题:

1.马拉车模板题(入门)

题目传送门

#include<bits/stdc++.h>
#include<cstdio>
#define ll long long
using namespace std;
const int MMAX=11000005;
char st[2*MMAX];
char s[MMAX];
int le[MMAX*2];
int main()
{
    scanf("%s",s);
    int len=strlen(s);
    st[0]='@';//字符串开头增加一个特殊字符,防止越界
    for(int i=1;i<=2*len;i+=2)
    {
        st[i]='#';
        st[i+1]=s[i/2];
    }
    st[len*2+1]='#';
    st[len*2+2]='$';//字符串结尾加一个字符,防止越界
    st[len*2+3]=0;
    int mx=0,po=0,ans=0;
    //mx为之前计算中最长回文子串的右端点的最大值,并且设取得这个最大值的位置为po
    for(int i=1;i<=len*2+1;i++)
    {
        /**-----这一段可以仔细钻研一下-------*/
        if(mx>i) le[i]=min(le[2*po-i],mx-i);
        else le[i]=1;
        while(st[i-le[i]]==st[i+le[i]]) le[i]++;
        /**-------------------------------------*/
        if(le[i]+i>mx)//更新mx和po
        {
            mx=le[i]+i;
            po=i;
        }
        ans=max(ans,le[i]);
    }
    printf("%d\n",ans-1);//注意最后结果是ans-1
    return 0;
}

2.复杂一点点的马拉车

题目传送门

#include<bits/stdc++.h>
#include<cstdio>-*
using namespace std;
const int MMAX=5005;
char st[2*MMAX],s[MMAX],temp[MMAX];
int le[2*MMAX];
int main()
{
    int t; scanf("%d",&t);
    while(t--)
    {
        int c1,c2,c3,c4,c5;
        scanf("%s",s);
        int len=strlen(s);
        int l=0,r=len-1;
        ///先寻找前缀后缀相等的
        while(r-l>=0&&s[r]==s[l]) l++,r--;
        c1=l,c2=r;c3=len;
        if(r-l<=0) printf("%s\n",s);
        else {
            ///然后对剩余的字符串跑一边马拉车
            for(int i=l;i<=r;i++) temp[i-l]=s[i];
            temp[r-l+1]=0;
            st[0]='@';
            int ll=strlen(temp);
            for(int i=1;i<=2*ll;i+=2)
            {
                st[i]='#';
                st[i+1]=temp[i/2];
            }
            st[2*ll+1]='#';
            st[2*ll+2]='$';
            st[2*ll+3]=0;
            int mx=0,ans=0,po=0,fm=0,f=-1;
            ///f=1记录是从左边开始,f=2记录从右边开始的,fm是回文串长度
            for(int i=1;i<=2*ll+1;i++)
            {
                if(mx>i) le[i]=min(mx-i,le[2*po-i]);
                else le[i]=1;
                while(st[i-le[i]]==st[i+le[i]]) le[i]++;
                if(le[i]+i>mx)
                {
                    mx=le[i]+i;
                    po=i;
                }
        /**-------更新fm和f----------------------------*/
                if(le[i]==i)
                {
                    if(le[i]-1>fm)
                    {
                        fm=le[i]-1;
                        f=1;
                    }
                }
                else if(le[i]+i==ll*2+2)
                {
                    if(le[i]-1>fm)
                    {
                        fm=le[i]-1;
                        f=2;
                    }
                }
        /**----------------------------------------------*/
            }
            for(int i=0;i<c1;i++) printf("%c",s[i]);
            if(f==1)
            {
                for(int i=0;i<fm;i++) printf("%c",temp[i]);
                for(int i=c2+1;i<c3;i++) printf("%c",s[i]);
                printf("\n");
            }
            else
            {
                for(int i=c2-fm+1;i<len;i++)
                    printf("%c",s[i]);
                printf("\n");
            }
        }
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值