最长回文字符串

1.问题解决的基本方法

```/*
*作者：侯凯
*说明：求最长回文字符串
*日期：2013-10-15
*/
#include<iostream>
using namespace std;
//字符串是否对称
bool isAym(char *cbegin, char *cend)
{
if(cbegin == NULL || cend ==NULL || cbegin > cend)
{
return false;
}
while(cbegin<cend)
{
if(*cbegin!=*cend)
{
return false;
}
cbegin++;
cend--;
}
return true;
}```

```//O(n*n*n)复杂度的子字符串
int getMaxSym(char * str)
{
if(str == NULL)
return 0;
int maxlength = 0, strlength = 0;
char *pFirst = str;
char *strEnd = str + strlen(str);
while(pFirst < strEnd)
{
char *pLast = strEnd;
while(pLast > pFirst)
{
if(isAym(pFirst, pLast))
{
strlength = pLast - pFirst + 1;
if(strlength > maxlength)
{
maxlength = strlength;
}
}
pLast --;
}
pFirst ++;
}
return maxlength;
}```

2.改进的解决方案

```//改进后的程序
int getMaxSym2(char * str)
{
if(str == NULL)
return 0;
int maxlength = 0;
char *ptag = str;
while(*ptag !='\0')
{
//奇数子字符串
char *left = ptag - 1;
char *right = ptag + 1;
int oddlenght = 1;
while(left >= str && *right != '\0' && *left == *right)
{
left--;
right++;
oddlenght += 2;
}
if(oddlenght > maxlength)
{
maxlength = oddlenght;
}
//偶数子字符串
left = ptag;
right = ptag + 1;
int evenlength = 0;
while(left >= str && *right != '\0' && *left == *right)
{
left--;
right++;
evenlength += 2;
}
if(evenlength > maxlength)
{
maxlength = evenlength;
}

ptag++;
}
return maxlength;
}```

3.manacher算法

```//预处理,将str：abba转换为: \$#a#b#b#a#\0(从1开始)
char * pre(char *str)
{
int length = strlen(str);
char *prestr = new char[2*length + 4];
prestr[1] = '\$';
for(int i=0;i<length;i++)
{
prestr[2*(i+1)] = '#';
prestr[2*(i+1)+1] = str[i];
}
prestr[2*length+2]='#';
prestr[2*length+3]='\0';
return prestr;
}```

```//manacher算法
int getMaxSym3(char *str)
{
char *prestr = pre(str);
int mx =0, pi=1;//边界和对称中心
int len = strlen(prestr);
//辅助数组
int *p = new int[len];
p[0] = 0;
for(int i=1;i<len;i++)
{
if(mx>i)
{
p[i]=min(mx-i,p[2*pi-i]);//核心
}
else
{
p[i]=1;
}
while(prestr[i-p[i]]==prestr[i+p[i]]&&i-p[i]>0&&i+p[i]<len)
{
p[i]++;
}
if(i+p[i] > mx)
{
mx = p[i] + i;
pi = i;
}
}
//最大回文字符串长度
int maxlen = 0;
for(int i=0;i<len;i++)
{
if(p[i]>maxlen)
{
maxlen = p[i];
}
}
delete []prestr;
delete []p;
return maxlen - 1;
}```

pi是最长回文字符串（淡蓝色）的中心，如果以j为中心的最大回文串如上如所示，那么i处的情况与j处相同（关于pi的两侧是对称的）。这样便减少了运算量，i的对称位置是2*pi-i。

```if(mx>i)
{
p[i]=min(mx-i,p[2*pi-i]);//核心
}```

（1）因为p[i]记录插入分隔符之后的回文字符串半径，所以以i为中心的回文字符串长度为2*p[i]-1。例如：bb=>#b#b#，中间#的半径为3，回文字符串长度为2*3-1；
（2）注意上面两个串的关系。 #b#b#减去一个#号的长度就是原来的2倍。即((2*p[i]-1)-1)/2 = p[i]-1，得证。

原文作者：侯凯
原文地址: https://www.cnblogs.com/houkai/p/3371807.html
本文转自网络文章，转载此文章仅为分享知识，如有侵权，请联系博主进行删除。