回文串编辑

本文介绍了一种用于查找字符串中最长回文子串的高效算法——Manacher算法,并提供了详细的实现步骤及示例代码。该算法通过巧妙地利用回文性质减少重复计算,能够在O(n)的时间复杂度内解决问题。

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

【题目描述】

操作包含两个步骤:

第一步:写一个很长的字符串(只包含小写)在纸上。例如,"abcde",而是'a'里面是不是真正的'a',这意味着如果我们定义的'b'才是真正的'a',那么我们可以推断,'c'才是真正的'b' ,'d'才是真正的'c'······,'a'才是真正的'z'。根据这一点,字符串"abcde"变为"bcdef"。

第二步:找出给定字符串中最长的回文串,回文字符串的长度必须等于或超过2。

【输入描述】

输入包含多个样例。

每个样例包含两个部分,一个字符和字符串,它们由一个空格分隔,代表真正的'a'和字符串,字符串的长度不会超过200000,所有输入字符必须为小写。

如果串的长度为n,它是从0标记为n-1。

【输出描述】

请以下两个步骤执行操作。

如果你找到一个回文串,输出它的起始位置和结束位置,下一行输出此回文串,或输出“无解!”;

如果有几个可用的答案,请选择其中最先出现的字符串。

【输入样例】

b babd

a abcd

 

【输出样例】

0 2

aza

No solution!

源代码:

#include<cstdio>
#include<cstring>
#include<algorithm> //包含min()。
using namespace std;
char keyword,s[200001],sss[200001];
int right,center,ans,num,point[200001]; //变量 right 表示当前回文子串的右边界,变量 center 表示当前回文子串的中心节点。
int main() //Manmcher算法。
{
    while (scanf("%c",&keyword)==1) //一直读入测试数据知道结束。
    {
        int key=keyword-'a'; //利用ASCII码来进行处理。
        memset(s,0,sizeof(s));
        memset(sss,0,sizeof(sss));
        memset(point,0,sizeof(point));
        right=0;
        center=0;
        num=0;
        ans=0; //全面初始化。
        char t;
        scanf("%c",&t); //除去空格。
        int length;
        scanf("%s",s);
        length=strlen(s);
        length=(length<<1)+1; //2*(string v1.0 的长度)+1=string v2.0的长度。
        for (int a=0;a<length;a++) //处理字符串。
          if (a&1)
            sss[a]=s[a>>1];
          else
            sss[a]='#';
        for (int a=0;a<length;a++) //依次处理字符。
        {
            point[a]=right>a?min(point[2*center-a],right-a):1; //如果已有回文子串右边界超过此节点,那么便有两种可能:以这个节点为中心的回文子串在这个大回文子串的范围内,或者超出这个范围。根据此理论将利用左对称点的信息来更新此节点。若不超过此节点,则只能普通处理。
            while (a>=point[a]&&sss[a+point[a]]==sss[a-point[a]]) //在允许的范围内进行边界的拓展。
              point[a]++;
            if (point[a]>num) //更新最值。
            {
                num=point[a];
                ans=a;
            }
            if (a+point[a]>right) //若新的右边界更大,则更新。
            {
                right=a+point[a];
                center=a;
            }
        }
        if (ans<=1) //无回文子串。
          printf("No solution!\n");
        else
        {
            int t1=(ans-point[ans]+2)>>1,t2=(ans+point[ans]-2)>>1; //可发现一规律:Point[i]=原以i为中心的回文子串长度+1。
            printf("%d %d\n",t1,t2);
            for (int a=t1;a<=t2;a++) //进行字符替换与处理。
                if (s[a]-key<'a')
                printf("%c",'z'+s[a]-'a'-key+1);
                else
                printf("%c",s[a]-key);
            printf("\n");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值