想起去年省选被D1t1虐抽了写了一个错误的nlogn的判断回文串50分= =,后来讲题的时候才发现这才是标准做法,着实虐掉了不少人,不过暴力似乎才30?不管了赶紧补档
Manacher 算法是一个高效的算法,像KMP一样。
算法简介:算法的目的是在O(n)的时间复杂度内找到一个字符串中各个字母所在的最大长度的回文串。
此算法用到了一个Rad[]数组的定义,Rad[i]表示回文的半径,即最大的j满足str[i-j+1...i] = str[i+1...i+j]。
我们的工作就是把全部的Rad[]求出来。
有两个结论:
(1): 对于一个整数k,如果 (1<=k<=Rad[i] && Rad[i-k] < Rad[i]-k ) 那么, Rad[i+k] = min( Rad[i-k], Rad[i]-k ).
(2) : 对于一个整数k,如果 (1<=k<=Rad[i] && Rad[i-k] > Rad[i]-k ) 那么, Rad[i+k] = min( Rad[i-k], Rad[i]-k ).
大致的算法过程:
char str[M];//start from index 1 int rad[M]; void Manacher() { int i,j,k; i=1;j = 0; while(i< =n) { while(str[i-j] == str[i+j+1] && i-j>0 && i+j+1 < = n) j++; rad[i] = j; k = 1; while(k<=rad[i] && rad[i-k] != rad[i]-k) { rad[i+k] = min(rad[i-k],rad[i]-k); k++; } i = i+k; j=max(j-k,0); } //Rad[] has obtain the ans }
最后来做一组模拟,算法过程就会很清楚了:
str[] = “acabbaabbaca”
str[1] != str[2],so
i: 1 2 3 4 5 6 7 8 9 10 11 12
str: a c a b b a a b b a c a
Rad: 0
str[2] != str[3], str[3]!=str[4] so
i: 1 2 3 4 5 6 7 8 9 10 11 12
str: a c a b b a a b b a c a
Rad: 0 0 0
str[4] = str[5] then check if str[3] == str[6] and so on, so
i: 1 2 3 4 5 6 7 8 9 10 11 12
str: a c a b b a a b b a c a
Rad: 0 0 0 2
then,rad[4-1]!=rad[4]-1;
so , rad[4+1] = min(rad[4-1],rad[4]-1) = 0;
i: 1 2 3 4 5 6 7 8 9 10 11 12
str: a c a b b a a b b a c a
Rad: 0 0 0 2 0
then,str[6] = str[7], then check if str[5] == str[8] and so on, so
i: 1 2 3 4 5 6 7 8 9 10 11 12
str: a c a b b a a b b a c a
Rad: 0 0 0 2 0 6
then,rad[6-1]!=rad[6]-1; rad[6+1] = min(rad[6-1],rad[6]-1) = 0;
rad[6-2]!=rad[6]-2; rad[6+2] = min(rad[6-2],rad[6]-1) = 2;
rad[6-3]!=rad[6]-3; rad[6+3] = min(rad[6-3],rad[6]-1) = 0;
rad[6-4]!=rad[6]-4; rad[6+4] = min(rad[6-4],rad[6]-1) = 0;
rad[6-5]!=rad[6]-5; rad[6+5] = min(rad[6-5],rad[6]-1) = 0;
so:
i: 1 2 3 4 5 6 7 8 9 10 11 12
str: a c a b b a a b b a c a
Rad: 0 0 0 2 0 6 0 2 0 0 0
at last rad[12] must be 0,
so we get the ans:
i: 1 2 3 4 5 6 7 8 9 10 11 12
str: a c a b b a a b b a c a
Rad: 0 0 0 2 0 6 0 2 0 0 0