原串: w aa bwsw f d
新串: # w# a # a # b# w # s # w # f # d #
在此之前要对字符串进行统一,即任意字符串在其所有字母之间插入特殊字符,这样可以将其总数变成奇数。(所有字符之间都插入特殊字符,则必有一个字符在中间是对称点,两边插入是防止越界和占位。)
void pk(int n,char str[])
{
int i;//记录数组的指针
int mx = 0;//最大长度
int id;//最大长度的半径值的位置。
int p[n];//用来存储每个字符的半径。
for(i=1; i<n; i++)//匹配这个字符串.此句也表明这个算法的时间复杂度为(n);最前面有占位符所以起始为一。
{
if( mx > i )
{
p[i] = MIN( p[2*id-i], mx-i );//下面有解释。
}
else
{
p[i] = 1;//任意一个字符,其半径最小为一。
}
for(; str[i+p[i]] == str[i-p[i]]; p[i]++);//判断是否相同,是则匹配下一个。可形成一个简易算法。
if( p[i] + i > mx )//当前匹配长度是否大于过去的最大长度。
{
mx = p[i] + i;//如大于,则替换。
id = i;
}
}
}
代码转自->Manacher;(并非原创);
p[i] = MIN( p[2*id-i], mx-i );// mx = p[i] + i;所以mx的值是可以大于i的,当且仅当p[i]已被匹配过,此过程参考。
例如:
str[4]//p[0]是特殊符,用来占位,故p[4]是第二个a。
p[4]=4;//则匹配p[5]时p[5]应直接等于3,因为与其对应的p[3]=3,其关于p[4]对称。所以匹配p[5]时是从p[8]开始的