manacher算法(马拉车)

这种算法通常用来解决一个字符串中的最长的回文串的长度是多少,嗯哼,然后时间复杂度为O(n),不过使用的范围很有局限性,但还是有用的。(重点在于短小快捷)
定义一些东西
r[i]表示以i为回文中心的最大回文半径
举个栗子: a b a b a
回文半径 :1 1 2 1 1
我觉得挺清楚的。
mx :表示找到的回文串的最右边界
p:表示mx的回文中心。
j:i关于p的对称点
mx’:表示mx关于p的对称点
为了避免奇偶性,在每个字符中间加一个特殊符号,是什么都行,还有首尾的符号要是别的,也不能一样,举个栗子 again
@a^b^a^b^a*
然后,激动人心的时候到了,我们分类讨论一下
j…………..mx’…………p…………..mx…………….i
______________________________________________________
这是一种情况 mx < i 这种情况代表了当前是一个未知的情况
所以r[i]>=1 (下限是1,因为最小就是只有它自己,上限未知),记住不是>=2,不要想当然。
然后展示一下第二种情况
mx’………………………..j…………………….p…………………..i……………………………….mx
——————————————————————————————————————————
这又可以分两种情况
第一种mx-i>r[j]
也就是说j的回文半径达不到mx’,又因为p左右两边具有对称性,所以r[i]=r[j]
因为j的回文半径达不到最大边界的对称点mx’,所以i也达不到最大边界mx。
第二种 mx-i<=r[j]
与上面相反,j可以跨越最大边界,所以r[i]的上限是未知的,下限是mx-i,也就是
r[i]>=mx-i。
至于上限,一位一位匹配就好
我觉得答案是最大半径或最大半径-1(看看边界是不是字母)
伪代码(我觉得是对的)pascal

uses math;
var
        s,s1:string;
        r:array[-10000..10000]of longint;
        mx,p,j,mx1,i,n,zd:longint;
begin
        //assign(input,'ma.in');
       // reset(input);
        read(s);
        n:=length(s);
        s1:='#';
        for i:=1 to n do
        begin
                s1:=s1+s[i]+'$';
        end;
        delete(s1,length(s1),1);
        s1:=s1+'@';
        for i:=1 to length(s1) do
        begin
                if(mx<=i)then
                begin
                        r[i]:=1;
                end
                else
                begin
                        r[i]:=min(r[2*p-i],mx-i);
                end;
                while(s1[i-r[i]]=s1[i+r[i]])do inc(r[i]);
                if(i+r[i]>mx)then
                begin
                        p:=i;
                        mx:=i+r[i];
                end;
        end;
        for i:=1 to length(s1) do
        begin
                if(s1[i+r[i]-1] in ['a'..'z'])then zd:=max(zd,r[i])
                else zd:=max(zd,r[i]-1);
        end;
        writeln(zd);
end.

讲得不清晰的地方,请见谅。
算法别名:马拉车
时间复杂度证明:(我也不懂)所以找了神犇的博客看了看,大意是mx的右移次数小于n

你可能感兴趣的:(算法)