问题描述
回文串是指aba、abba、cccbccc、aaaa这种左右对称的字符串。
输入一个字符串Str,输出Str里最长回文子串的长度。
方法一:暴力求解
遍历每一个子串,再判断这个子串是不是回文串,最后判断这个串是不是最长的回文子串。
遍历子串的复杂度是O(n^2),判断是不是回文串的复杂度是O(n),所以这个算法的复杂度是O(n^3)。
方法二:动态规划法
用一个二维的数组ai来表示从第i位到第j位的子串是不是回文串,在判断从i到j的子串是不是回文串时,可以先看i+1到j-1是不是回文串,再判断i位和j位是不是相同。这个算法中,遍历子串的复杂度仍然是O(n^2),但是判断是不是回文串的复杂度降到了O(1),所以这个算法的复杂度是O(n^2)。但是这个算法占据了O(n^2)的空间。
方法三:中心扩展法
顾名思义,任何一个回文串都有一个对称轴,从这个中心的位置开始,向两边扩展,可以得到以此为中心的最长回文串。但是要注意,这个对称轴的位置,可能是一个字符,也可能是两个字符中间。遍历对称轴的位置,复杂度是O(n),找到以此对称轴为中心的最长回文串,其复杂度是O(n),所以此算法的复杂度是O(n^2)。这个算法比动态规划好的地方是其空间复杂度只有O(1)。
#include <iostream>
#include <cstring>
using namespace std;
#define LEN 1000
int main(){
char str[LEN];
cin>>str;
int len=strlen(str);
int maxlen=0,mx;
for(int i=0;i<len;i++){
mx=1;
for(int j=1;(i-j>=0)&&(i+j<len);j++){
if(str[i-j]==str[i+j])
mx+=2;
else break;
}
maxlen=maxlen>mx?maxlen:mx;
}
for(int i=0;i<len;i++){
mx=0;
for(int j=0;(i-j>=0)&&(i+j+1<len);j++){
if(str[i-j]==str[i+j+1])
mx+=2;
else break;
}
maxlen=maxlen>mx?maxlen:mx;
}
cout<<maxlen<<endl;
return 0;
}
方法四:manacher算法
预处理
在字符串的开始加上一个'$'符,然后在每个字符中间插上一个'#'。比如,字符串ss='abac',处理之后是str='$#a#b#a#c#'。接下来的计算针对处理后的字符串。
len数组
然后定义一个len数组,len[i]表示的是以str[i]为中心的最长回文串的半径。
仍以上面的字符为例。str='$#a#b#a#c#',以str[0]为中心的最长回文串是'$',其半径是1;以str[4]为中心的最长回文串是'#a#b#a#',其半径是4;len数组为{1,1,2,1,4,1,2,1,2,1}。可以发现,len[i]-1的值,就是原字符串ss中对应的回文串的长度(以#为中心的是偶长度的回文串,以字符为中心的是奇长度的回文串)。
计算len数组
算法的关键在于在计算len数组时,可以利用前面的结果进行优化。
引入变量maxright表示当前访问到的所有回文子串,所能触及的最右一个字符的位置;同时记录maxright所对应的回文串的对称轴的位置,记为pos。
复杂度分析
考虑p的值的变化,在计算的过程中,p只会增加不会减少,当p增加到strlen(str)时,每个位置的len数组的值都可以立即计算得出。所以算法的复杂度是O(n)。
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
#define N 100004
string str,ss;
int len[2*N+1];
int main()
{
cin>>ss;
str="$#";
for(unsigned int i=0;i<ss.size();i++)
{
str+=ss[i];
str+="#";
}
// cout<<str<<endl;
int pos=0,p=0,j=0;
len[0]=1;
for(unsigned int i=1;i<str.size();i++)
{
j=2*pos-i;
if(p>i)
len[i]=(len[j]>p-i)?(p-i):(len[j]);
else
len[i]=1;
while(i+len[i]<str.size()&&i-len[i]>=0&&str[i+len[i]]==str[i-len[i]])
len[i]++;
if(i+len[i]>=p)
{
pos=i;
p=i+len[i];
}
}
int ans=0;
for(int i=0;i<str.size();i++)
{
// cout<<len[i]<<" ";
ans=(len[i]-1>=ans)?len[i]-1:ans;
}
// cout<<endl;
cout<<ans<<endl;
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。