这种算法通常用来解决一个字符串中的最长的回文串的长度是多少,嗯哼,然后时间复杂度为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