hdu3068+hdu3294 最长回文字符串的manacher算法

本文详细介绍Manacher算法原理及实现步骤,通过实例解析如何求解最长回文子串问题,并提供两段C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

两道题目描述都差不多,关键问题都是求最长回文子串,这里讲解一下manacher算法。

对于一个字符串,记初始下标为0,回文串有偶回文和奇回文之分,可以在字符串任意两个字符之间加入’#‘,使得奇回文还是奇回文,偶回文变成奇回文。

然后增加一个数组p,p[i]表示以i为中心的最长回文串的半径。增加一个整型变量mx,记录所有已经计算过的部分的回文串能达到的最右端的部分,增加一个整型变量id,记录已经计算过的部分的最大mx的中心,

例如对asabba这个字符串,边模拟边讲思想。

变成@#a#s#a#b#b#a#,@相当于终结符合,保证它在输入字符串中没有出现过,则每次匹配到此处时不可能匹配成功,防止数组越界。

初始id=mx=p[0]=0。

接下来对p[1],试想,如果1<mx,即我当前正要计算的位置在之前已经计算过的最大回文串最右边的左边,那么在此处与id对称的位置上,一定与此处的字符匹配,因为id的匹配回文长度长于当前位置,然后,既然处于已经匹配成功的串内部,那么,与id对应位置的哪个字符的最长回文长度对当前位置就是可用的,如果哪个长度小于mx-i,那么毫无疑问,那边能回文,而我这边与那边完全对称,那我这边肯定也回文,如果大于mx-i,那么至少在mx-i的长度内是完全回文的,那么当前位置的最小回文长度为mx-i。求得最小值之后,就要进行简单模拟,试图增大回文串长度,直至匹配失败。

由于1>mx=0,之前的所有计算结果都不涉及1,故前面所有内容对当前位置无用,p[1]=0。试图增大发现s[0]!=s[2],匹配失败,p[1]=0,id=mx=1。

由于2>mx=1,同上,p[2]=0。试图增大发现s[1]==s[3],s[0]!=s[4],故p[2]=1,此时最大位置发生变化,mx=i+p[i]=3,id=2。

由于3==mx,之前匹配结果对我有用,1是3关于id的对称位置,由于p[1]==0,mx-i==0,则p[3]=0。试图增大,增大失败,p[3]=0,i+p[i]<=mx,没有改变mx的最大值,故id和mx不变。

由于4>mx,同上读者自己推,得p[4]=3,mx=4+p[4]=7,id=4。

由于5<mx,之前结果对当前位置有用,3是5关于4的对称点,p[3]=0,而5和3对称,则p[5]=0。试图增大,得p[5]=0。

由于6<mx,之前结果对当前位置有用,2是6关于4的对称点,p[2]=1,而2和6对称,且mx-6>=p[2],证明6到mx部分和2-p[2]到2的部分对称,2和6之内的部分对称,2形成的最长回文串在4形成的最长回文串之内,p[6]=p[2](算法精髓,动态规划思想,读者认真体会)。然后试图增大,得p[6]=1。

由于7<=mx,之前结果有用,算的p[7]=p[1]=0。试图增大,p[7]=0。

由于8>mx,之前结果无用,p[8]=0。朴素算法继续试图增大,p[8]=1,mx=9,,id=8。

由于9=mx,之前结果有用,算的p[9]=0。试图增大,得p[9]=4,mx=13=字符串长度,id=9。

此后的部分其实可以不算,因为之后以任意一个字符为中心形成的回文串最长也只能到字符串尾部,而上面部分已达到尾部,则上面部分形成的回文串一定长于此后部分的回文串,可以直接跳出。

算法的关键部分在于已经求得的回文串的利用,对称的字符串,其子字符串相应位置必然对称,然后从前往后求时,对对称部分只需要求一次便可,节省了时间。

网上说算法是o(n)的,但感觉不是o(n)的,具体时间复杂度随机性应该比较大。

hdu3068代码(模板):

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

char s[222222];
char s1[111111];
int p[222222];

int min(int a,int b)
{
    return a>b?b:a;
}

void getp()
{
    int id=0,mx=0;
    p[0]=0;
    int l=strlen(s);
    for (int i=1;i<l;i++)
    {
        p[i]=mx<i?0:min(p[id*2-i],mx-i);
        while (s[i-p[i]-1]==s[i+p[i]+1])
            p[i]++;
        if (p[i]+i>mx)
        {
            mx=p[i]+i;
            id=i;
        }
    }
}

int main()
{
    while (~scanf("%s",s1))
    {
        int l=strlen(s1);
        s[0]='@';
        for (int i=0;i<=l;i++)
        {
            s[i*2+1]='#';
            s[i*2+2]=s1[i];
        }
        getp();
        int ans=0;
        l=strlen(s);
        for (int i=2;i<l;i++)
        {
            if (p[i]>ans)
                ans=p[i];
        }
        cout<<ans<<endl;
    }
}

hdu3294代码(输出麻烦点):

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>

using namespace std;

char s1[200002];
char s[400004];
char pp;
int p[400004];

int min(int a,int b)
{
    return a>b?b:a;
}

void getp()
{
    int id=0,mx=0;
    int l=strlen(s);
    p[0]=0;
    for (int i=1;i<l;i++)
    {
        p[i]=mx<i?0:min(p[id*2-i],mx-i);
        while (s[i-p[i]-1]==s[i+p[i]+1])
            p[i]++;
        if (i+p[i]>mx)
        {
            mx=p[i]+i;
            id=i;
        }
    }
}

int main()
{
    while (~scanf("%c%s",&pp,s1))
    {
        s[0]='@';
        int l=strlen(s1);
        for (int i=0;i<=l;i++)
        {
            s[2*i+1]='#';
            s[2*i+2]=s1[i];
        }
        getp();
        /*
        for (int i=0;i<strlen(s);i++)
            cout<<i<<" ";
        cout<<endl;
        for (int i=0;i<strlen(s);i++)
            cout<<s[i]<<" ";
        cout<<endl;
        for (int i=0;i<strlen(s);i++)
            cout<<p[i]<<" ";
        cout<<endl;
        */
        int id,ans=0;
        for (int i=2;i<=l*2;i++)
        {
            int t=p[i];
            if (t>ans)
            {
                ans=t;
                id=(i+1)/2-1;
                id=id-(t+1)/2+1;
                if (i%2==1)
                    id--;
            }
        }
        if (ans<=1)
        {
            cout<<"No solution!"<<endl;
            getchar();
            continue;
        }
        cout<<id<<" "<<id+ans-1<<endl;
        for (int i=id;i<id+ans;i++)
        {
            char a=s1[i];
            int t=pp-'a';
            a=a-t;
            if (a<'a')
                a=a+26;
            cout<<a;
        }
        cout<<endl;
        getchar();
    }
}


内容概要:本文深入探讨了金属氢化物(MH)储氢系统在燃料电池汽车中的应用,通过建立吸收/释放氢气的动态模型和热交换模型,结合实验测试分析了不同反应条件下的性能表现。研究表明,低温环境有利于氢气吸收,高温则促进氢气释放;提高氢气流速和降低储氢材料体积分数能提升系统效率。论文还详细介绍了换热系统结构、动态性能数学模型、吸放氢特性仿真分析、热交换系统优化设计、系统控制策略优化以及工程验证与误差分析。此外,通过三维动态建模、换热结构对比分析、系统级性能优化等手段,进一步验证了金属氢化物储氢系统的关键性能特征,并提出了具体的优化设计方案。 适用人群:从事氢能技术研发的科研人员、工程师及相关领域的研究生。 使用场景及目标:①为储氢罐热管理设计提供理论依据;②推动车载储氢技术的发展;③为金属氢化物储氢系统的工程应用提供量化依据;④优化储氢系统的操作参数和结构设计。 其他说明:该研究不仅通过建模仿真全面验证了论文实验结论,还提出了具体的操作参数优化建议,如吸氢阶段维持25-30°C,氢气流速0.012g/s;放氢阶段快速升温至70-75°C,水速18-20g/min。同时,文章还强调了安全考虑,如最高工作压力限制在5bar以下,温度传感器冗余设计等。未来的研究方向包括多尺度建模、新型换热结构和智能控制等方面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值