方法一:分治
回文有两种类型:奇数长度的回文和偶数长度的回文
字符串表示为s,s的最长回文子串用ans表示。
奇数长度回文:
- 以
i为对称中心,对称半径为j(j>=0) (i-j) ... i ... (i+j)总长度是2j-1- 在
i-j和i+j在合理范围内时,如果有s[i-j]==s[i+j],而且ans的长度小于2j-1,则令ans=s.substr(i-j,2j-1),然后j++,继续比较s[i-j]和s[i+j],直到不相等,再重新选择对称中心,重新从上面的1开始执行。
偶数长度回文:
- 以
i和i+1为对称中心,半径为j(j>=1)。 (i-j+1) ... i,i+1 ... (i+j)总长度是2j- 在
i-j+1和i+j在合理范围内时,如果有s[i-j+1]==s[i-j],而且ans的长度小于2j,则令ans=s.substr(i-j+1,2j).
实现:
string max_pal(string& s,int n)
{
string ans;
for(int i=0;i<n;i++)
{
//回文长度为奇数
for(int j=0;i-j>=0&&i+j<n&&s[i-j]==s[i+j];j++)
{
if(ans.length()<2*j-1)
ans=s.substr(i-j,2*j-1);
}
//回文长度为偶数
for(int j=1;i-j+1>=0&&i+j<n&&s[i-j+1]==s[i-j];j++)
{
if(ans.length()<2*j)
ans=s.substr(i-j+1,2*j);
}
}
return ans;
}
方法二:Manacher方法
统一考虑长度为奇数和偶数的回文串
- 在字符串首尾和每个字符中间都插入一个特殊字符,使得回文串都变成奇数长度的。
- 比如
abcdc,插入特殊符号后变成#a#b#c#d#c
- 比如
- 定义一些符号
- 数组
p[i]表示以i为中心的回文半径长度。 id表示最大回文的mx表示最大回文子串的右边界,即mx=id+p[i]
- 数组
- 在从
s[0]扫描到s[n-1]的过程中:
若mx>i,有p[i]=min(p[2*id-1],mx-i)。其中2*id-1是i关于id对称的下标j=2*id-1.
- 当
p[i]<mx-i时,以s[j]为中心的回文串全部包含在以s[id]为中心的回文串中,而且i,j对称,以s[i]为中心的回文串必定也包含在s[id]为中心的回文串中.有p[i]=p[j].
- 当
p[i]>=mx-i时,s[i]的回文半径至少为mx-i,向右扩展的部分要比较后才知道是不是构成回文串。
- 当
i>=mx是,只能先让p[i]=1,再进行后续匹配。
- 当
实现:
string Manacher(string &s)
{
//字符串处理
if(s.length()<=1)
return s;
int n=s.length();
string str="#";
for(int i=0;i<n;i++)
{
str+=s[i];
str+='#';
}
n=str.length();
vector<int>p(n);
int mx=id=0;
int best_mx=bext_id=0;
//从0开始遍历字符串
for(int i=0;i<n;i++)
{
if(mx>i)
p[i]=min(p[2*id-i],mx-i);
else
p[i]=1;
while(i-p[i]>=0&&i+p[i]<n&&str[i-p[i]]==str[i+p[i])
p[i]++;
if(p[i]+i>k)
{
id=i;
mx=p[i]+i;
if(mx-id>best_mx-best_id)
{
best_mx=mx;
best_id=id;
}
}
}
string ans;
for(int i=2*best_id-best_mx+1;i<bext_mx;i++)
{
if(str[i]!='#')
ans+=str[i];
}
return ans;
}
时间复杂度为O(n)


504

被折叠的 条评论
为什么被折叠?



