题目:Longest Palindromic Substring
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
暴力解决会出现TLE错误。
string longestPalindrome(string s) {
int length=0,l=0,r=0;
for (int len=s.length();len>=0;--len)
{
for (int left=0;left+len<s.length();++left)
{
int right=left+len,flag=1;
for (int k=left;k<=(left+right)/2;k++)
if (s[k]!=s[left+right-k])
{
flag=0;
break;
}
if (flag&&right-left+1>length)
{
length=right-left+1;
l=left;
r=right;
break;
}
}
if (length!=0) break;
}
return s.substr(l,r-l+1);
}
};
动态规划,如果是字符串[i,j]是回文字符串,则[i+1,j-1]是回文字符串(至少长度为3),所以将加个二维状态数组p[i,j]解释从i到j是否满足是回文字符串。
class Solution {
public:
string longestPalindrome(string s) {
const int length=s.size();
int maxlength=0;
int start;
bool P[length+5][length+5]={false};
for(int i=0;i<length;i++)//初始化准备
{
P[i][i]=true;
if(i<length-1&&s.at(i)==s.at(i+1))
{
P[i][i+1]=true;
start=i;
maxlength=2;
}
else if (length==1)
{
start=i;
maxlength=1;
}
}
for(int len=3;len<=length;len++)//子串长度
for(int i=0;i<=length-len;i++)//子串起始地址
{
int j=i+len-1;//子串结束地址
if(P[i+1][j-1]&&s.at(i)==s.at(j))
{
P[i][j]=true;
maxlength=len;
start=i;
}
}
return s.substr(start,maxlength);
}
};
中心对称,中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展(奇数扩展,偶数扩展),这样来找最长的子回文串。算法复杂度为O(N^2)。
class Solution {
public:
string longestPalindrome(string s) {
const int length=s.size();
int maxlength=0;
int start;
if (length==1)
{
start=0;
maxlength=1;
}
else
{
start=0;
maxlength=1;
for(int i=0;i<length;i++)//长度为奇数
{
int j=i-1,k=i+1;
while(j>=0&&k<length&&s.at(j)==s.at(k))
{
if(k-j+1>maxlength)
{
maxlength=k-j+1;
start=j;
}
j--;
k++;
}
}
for(int i=0;i<length;i++)//长度为偶数
{
int j=i,k=i+1;
while(j>=0&&k<length&&s.at(j)==s.at(k))
{
if(k-j+1>maxlength)
{
maxlength=k-j+1;
start=j;
}
j--;
k++;
}
}
}
if(maxlength>0)
return s.substr(start,maxlength);
return NULL;
}
};
manacher算法,通过记录已匹配的最右位置和对应的对称中心来跳过一些没用的比较。
class Solution {
public:
string longestPalindrome(string s) {
char tmp[2*s.length()+3]={0};
int p[2*s.length()+3]={0};
int id=0,maxlen=0,l=0,len=s.length();//id和maxlen为最长的回文串的中心和中心到最右边长度。
for (int i=len-1;i>=0;i--)//因为基于中心对称,所以要转成奇数个,添加个#
{
tmp[2*i+2]=s[i];
tmp[2*i+1]='#';
}
tmp[0]='*';//防止比较越界
tmp[2*len+1]='#';
tmp[2*len+2]='$';
for (int i=2;i<=2*len;i++)
{
//三种情况的总结,i-k在里面,外面,和边界重合。
if (id+p[id]>i)
p[i]=min(p[2*id-i],p[id]-(i-id));
else
p[i]=1;
while (tmp[i-p[i]]==tmp[i+p[i]]) ++p[i];
if (id+p[id]<i+p[i]) id=i;
if (maxlen<p[i])
{
maxlen=p[i];
if (maxlen==2)
l=0;
else
l=(i-maxlen+2)/2-1;
}
}
string res="";
for (int i=0,j=l;i<maxlen-1;i++,j++)
{
res+=s[j];
}
return res;
}
};