manacher
用法O(n)求最长回文子串
对于回文串有两种情况:
- 对于中间一个元素对称;
- 对于中间一个空格对称;
为了两种情况的适应性,我们可以把他们总结归纳以下,对于第二种的我们直接加入一个不存在的元素表示空格,对于第一种显然是没有影响的,而且可以发现,这时候回文串的长度等于当前元素能扩展到的最长距离,因为对于i的左边一共有len/2个元素,右边一共有len/2个空格,即证;
思想利用回文串的特性(以中间一个元素对称),我们每一次考虑第i个元素时,可以通过看这个元素是否在一个回文串里面,如果在,那么就先找到与他对称的那个元素进行比较,直接得到最小的回文长度,然后对这个长度进行一次比较(超过之前覆盖当前元素i的回文的话就无效了),看是否符合条件不在的话就直接暴力扩展。
核心部分
int cur=(i>pos+vis[pos])?0:min(vis[2*pos-i],pos+vis[pos]-i);//上面黄色部分
基本代码
for(i=0;i<=2*len+1;i++)
{
a[i]='#';
}
for(i=0;i<len;i++) a[i*2+1]=s[i];
len=i*2+1;
int pos=0,ans=0;
for(i=0;i<len;i++)
{
int cur=(i>pos+vis[pos])?0:min(vis[2*pos-i],pos+vis[pos]-i);
while(1){
if(a[i-cur]!=a[i+cur]||(i-cur<0||i+cur>len)) break;
else cur++;//暴力扩展
}
cur--;
if(cur+i>pos+vis[pos]) pos=i;//更新最远回文串控制区域
vis[i]=cur;
ans=max(ans,cur);