概述
计算一个最长回文子序列的朴素算法的时间复杂度为O( n^2 ),而该算法使时间复杂度降至O( n )。
该算法利用的原理为:当一个小回文序列在一个大回文序列中时,其小回文序列在大回文序列的对称位置的序列与原小回文序列一致。
利用这个原理,可以减少单一回文序列的计算量。
另外,为使代码更加简练,可以对初始字符串进行处理,使回文序列的长度变成奇数。
伪代码
GET_PANLINDROMIC_STRING_LENGTH( S, pos, r )
l = 2*pos - r
while l >= 0 and r < S.size
if S[l++] != S[r++]
return r - pos - 1
return r - pos
MANACHER( S )
let C is a array.
pos = 0
C[0] = 0
for i=1 to S.size
r = i
l = 2*ptr - r
if C[pos] + ptr <= r
C[i] = GET_PANLINDROMIC_STRING_LENGTH( S, i, i+1 )
else if l - C[l] > pos - C[pos]
C[r] = C[l]
else
C[i] = GET_PANLINDROMIC_STRING_LENGTH( S, i, pos + C[pos] )
if r + C[r] > pos + C[pos]
pos = r
return C
代码实现
class Manacher
{
public:
Manacher( std::string str, char* buf );
int getPanlindromicStringLength( int pos, int r );
int getMaximumLength( int* buf );
private:
std::string str;
};
Manacher::Manacher( std::string str, char* buf )
{
int len = str.length();
buf[0] = '$';
for( int i=0; i<len; ++i ) {
buf[i*2+1] = '#';
buf[i*2+2] = str[i];
}
buf[len*2+1] = '#';
buf[len*2+2] = '\0';
this->str = std::string( buf );
};
int Manacher::getPanlindromicStringLength( int pos, int r )
{
int l = 2*pos - r;
int len = str.length();
while( l >= 0 && r < len ) {
if( str[l--] != str[r++] ) {
return r-pos-1;
}
}
return r-pos;
}
int Manacher::getMaximumLength( int* buf )
{
int pos = 0;
buf[pos] = 1;
for( int i=1; i<str.length(); i++ ) {
int r = i;
int l = 2*pos - r;
if( buf[pos] + pos <= r ) {
buf[i] = getPanlindromicStringLength( i, i+1 );
}
else if( l - buf[l] > pos - buf[pos] ) {
buf[i] = buf[l];
}
else {
buf[i] = getPanlindromicStringLength( i, pos+buf[pos]);
}
if( r+buf[r] > pos+buf[pos] ) {
pos = r;
}
}
int result = -1;
for( int i=0; i<str.length(); ++i ) {
if( buf[i] > result ) {
result = buf[i];
}
}
return result-1;
}