马拉车算法

Manacher算法,又叫“马拉车”算法
可以在时间复杂度为O(n)的情况下求解一个字符串的最长回文子串长度的问题。

马拉车算法

回文分为偶回文(abba)和奇回文(abcba)。在处理奇偶回文之间有差异,所以用到了一个技巧

在 (每个字符之间和开头) 插入一个无关的字符,

比如说: abbahopxpo 转换为 $#a#b#b#a#h#o#p#x#p#o# ( ’ $ ’ 是防止越界 )

起初有一个偶回文abba和一个奇回文opxpo,被转换为#a#b#b#a#和#o#p#x#p#o#,长度都转换成了奇数。

回文半径数组radius

回文半径数组radius是用来记录以每个位置的字符为回文中心求出的回文半径长度,如下图所示
在这里插入图片描述
可以看出,radius[i] - 1正好是原字符串中最长回文串的长度。

求解回文半径数组radius

mx 代表以 id 为中心的最长回文的右边界,也就是mx = id + radius[id]。

在这里插入图片描述
如图,mx 到 mx 关于 id 对称点之间是一个回文串,
要是从 j 到 mx 的对称点 之间存在回文串,那么 i 到 mx 之间也一定会存在回文串
那么以 i 为对称点的回文串的长度最少是 m i n ( r a d i u s [ j ] , m x − i ) min(radius[j], mx-i ) min(radius[j],mxi)
并且 j = 2 ∗ i d − i j= 2 * id - i j=2idi
所以最终优化的是 r a d i u s [ i ] = m i n ( r a d i u s [ 2 ∗ i d − i ] , m x − i ) radius[i] = min(radius[2 * id - i], mx - i) radius[i]=min(radius[2idi],mxi)

code
/*
最长回文
HDU - 3068
https://cn.vjudge.net/problem/HDU-3068
题面:最长回文长度
解法:马拉车算法
*/
#include <bits/stdc++.h>
using namespace std;
#define maxn 300005
int radius[maxn];
char s[maxn];
char s_new[maxn];
int init(){
  int len=strlen(s);
  s_new[0]='$';
  s_new[1]='#';
  int j=2;
  for(int i=0;i<len;i++){
    s_new[j++]=s[i];
    s_new[j++]='#';
  }
  s_new[j]='\0';
  return j;
}
int Manacher(){
  int len=init();
  int ans=-1;
  int id;
  int mx=0;
  for(int i=1;i<len;i++){
    if(i<mx) radius[i]=min(radius[2 * id - i], mx - i);
    else radius[i]=1;
    while(s_new[i-radius[i]]==s_new[i+radius[i]]){
      radius[i]++;
    }
    if(mx<i+radius[i]){
      id=i;
      mx=i+radius[i];
    }
    ans=max(ans,radius[i]-1);
  }
  return ans;
}
int main(){
  while(~scanf("%s", s)){
    printf("%d\n", Manacher());
  }
}

参考:Manacher算法
参考:Manacher算法的详细讲解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值