Manacher算法笔记

定义:

一种简单的寻找回文子串的算法。可以在O(N)的时间复杂度内,求出以每个字母为对称中心的回文子串。

属于奇技淫巧?回文串的题很少啊。
我们还有后缀数组求回文子串的方法,可以做到 O(Nlog2N) ,但是写起来烦,(主要是我不会写)。

模板

#define min(a,b) ((a)<(b)?a:b)
void Manacher(char *a)
 {
    int MaxId,id;
    for(int i=1;a[i]!='\0';i++)
      {
         if(MaxId>i) p[i]=min(p[2*id-i],MaxId-i);
         else p[i]=1;
         while(a[i+p[i]]==a[i-p[i]]) p[i]++;
         if(p[i]+i>MaxId){
               MaxId=p[i]+i;
               id=i;
           }
      }
 }
/*以下是构造的片段*/
for(i=1;b[i]!='\0';i++)
    {
          a[i<<1]=b[i];
          a[(i<<1)+1]='#';
    }
a[0]='?',a[1]='#';
n=(i<<1)+2,a[n]=0;

说明

定义一些符号:

原串: S0
处理后保证奇数长度的串: S
反串:S(即为 S 前后倒置的串)
数组:P 记录以每个字符为中心的最长回文半径的数组(最小为1,即只含有其本身)

预处理

S0 两个两个字符之间插入不属于原字符集的字符,将其转化为 S

引理

P[i]1是以 Si 为中心的回文子串在原串中的长度。

算法

我们接下来还要再定义两个数字,即:

MaxId 为之前的回文串中匹配到的最远位置
id 就是 MaxId 被取到时的 i

对于i=2idi,容易看出 i i 关于id对称。但如果这一部分的回文串,翻过去超出了 MaxId ,那我们就不能保证原有的对称性。那么为了保证正确性,我们在这两种可能性中取最小,最终我们有 P[i]=min{P[2idi],MaxIdi} 。但此时的 P[i] 不是最佳解,而只是最小值。我们通过迭代,可以求到 P[i] 的最优解。最终统计时,统计 P <script id="MathJax-Element-1142" type="math/tex">P</script>数组的最大值即可。

HDU3068

裸题。
(也没什么好题了)

#include <stdio.h>
#define M 110010
char b[M],a[M<<1];
int p[M<<1];
#define min(a,b) ((a)<(b)?a:b)
#define max(a,b) ((a)>(b)?a:b)
int main() 
 {
    int i,n,id,MaxL,MaxId;
    while(scanf("%s",b+1)!=EOF)
     {
        MaxL=MaxId=0;
        for(i=1;b[i]!='\0';i++)
         {
            a[i<<1]=b[i];
            a[(i<<1)+1]='#';
           }
        a[0]='?',a[1]='#';
        n=(i<<1)+2,a[n]=0;
        for(i=1;i<n;i++)
         {
            if(MaxId>i) p[i]=min(p[2*id-i],MaxId-i);
            else p[i]=1;
            while(a[i+p[i]]==a[i-p[i]]) p[i]++;
            if(p[i]+i>MaxId) {
                  MaxId=p[i]+i;
                  id=i;
             }
            MaxL=max(MaxL,p[i]);
         }
        printf("%d\n",MaxL-1);
      }
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值