这里在网上搜集了三种方法
(1) 用动态规划的思想来做,isP[i][j]可以表示该字符串是否为回文子串,如果是则长度是j-i+1,否则不记录长度,最后比较找到最大的长度。动态规划方程是isP[i][j]=1(i==j.i+1=j,i+2=j,也就是j-i<=2),isP[i][j]=s[i]==s[j]&&isP[i+1][j-1](j-i>2)。
代码如下:
class Solution {
public:
string longestPalindrome(string s) {
//用动态规划做
int start=0,len=1;
int n=s.size();
int isP[n][n]={0};//将所有元素初始化为0,表示i至j的子串是非回文子串
//遍历矩阵(二维数组的左下三角部分,i<j)
for(int j=1;j<n;j++)
for(int i=0;i<j;i++){
if(j-i<=2){
isP[i][j]=s[i]==s[j];
}else{
isP[i][j]=(s[i]==s[j])&&isP[i+1][j-1];
}
if(isP[i][j]&&(len<j-i+1)){
start=i;
len=j-i+1;
}
}
return s.substr(start,len);
}
};
(2)中心扩展:逐个遍历字符,以字符为中心,向两边扩散,直到不满足回文子串的性质为止,记录此段回文子串的开始位置和长度。比较回文子串中最大的一个,返回。需要注意的是回文子串有aba,abba这两种形式,因此当遍历到某一个字符时需要考虑中间位置的字符是奇数和偶数的形式,也就是说对于某一个字符需要遍历两次。复杂度为O(n2)
代码如下:
class Solution {
public:
string longestPalindrome(string s) {
int start=0,len=1,left,right;
for(int i=0;i<s.size()-1;i++){
if(s[i]==s[i+1]){ //查看偶数的形式,abba
left=i;
right=i+1;
findPalindrome(s,left,right,start,len);
}
//查看奇数的形式,aba
left=right=i;
findPalindrome(s,left,right,start,len);
}
return s.substr(start,len);
}
void findPalindrome(string& s, int left, int right,int& start,int& len)
{
int width=0,step=1;
while(left-step>=0&&right+step<s.size())
{
if(s[left-step]!=s[right+step]){
break;
}
++step;
}
width=right-left+2*step-1; //right-left+1+2*(step-1)
if(width>len)
{
len=width;
start=left-step+1; //left-(step-1)
}
}
};
(3) 马拉车算法,原理可见 博客http://www.cnblogs.com/grandyang/p/4475985.html
代码如下:
class Solution {
public:
string longestPalindrome(string s) {
//用马拉车算法做
string str="*#";
for(int i=0;i<s.size();i++)
{
str+=s[i];
str+='#';
}
int num[str.size()]={0};//num[i]表示i处的回文串半径
int mx=0,id=0,mid=0,len=0; //mx表示回文子串可以延伸到的最右端位置,id为mx状态下的中心点
for(int i=1;i<str.size();i++)
{
num[i]=mx >i ? min(num[2*id-i],mx-i):1; //id-(i-id)
while(str[i+num[i]]==str[i-num[i]]){
++num[i]; //求num[i]
}
if(mx<i+num[i]){
mx=i+num[i];
id=i;
}
if(len<num[i]){
len=num[i];
mid=i;
}
}
return s.substr((mid-len)/2,len-1);
}
};