【暴力枚举】
求最长回文串最容易的方法就是暴力枚举,求出字符串的每一个子串,然后判断是不是回文,找到最长的那个回文串
求每一个子串的时间复杂度为 O(N^2),判断一个子串是不是回文时间复杂度为 O(N),总的时间复杂度为 O(N^3)
string str;
void longestPalindrome(){
int len=str.size();//字符串长度
int maxlen=1;//最长回文串长度
int start=0;//最长回文串起始地址
for(int i=0;i<len;i++){//起始地址
for(int j=i+1;j<len;j++){//结束地址
//判断是不是回文
int temp1=i,temp2=j;
while(temp1<temp2 && str.at(temp1)==str.at(temp2)){
temp1++;
temp2--;
}
if(temp1>=temp2&&j-i+1>maxlen){
start=i;//更新回文串起始地址
maxlen=j-i+1;//更新回文串长度
}
}
}
str=str.substr(start, maxlen);
}
int main(){
cin>>str;
longestPalindrome();
cout<<str<<endl;;
return 0;
}
【中心扩展法】
中心扩展就是将给定的字符串的每一个字母当做中心,然后向两边扩展,这样来寻找最长的回文串。其需要考虑两种情况:长度为奇数的回文串、长度为偶数的回文串。
时间复杂度为 O(N^2)
string str;
void longestPalindrome(){
int len=str.size();//字符串长度
int maxlen=1;//最长回文串长度
int start=0;//最长回文串起始位置
//长度为奇数的回文串
for(int i=0;i<len;i++){//枚举中心位置
int left=i-1,right=i+1;//以i为中心向左右两边扩展
while(left>=0 && right<len && str.at(left)==str.at(right)){
if(right-left+1>maxlen){
start=left;//更新回文串起始位置
maxlen=right-left+1;//更新回文串长度
}
left--;
right++;
}
}
//长度为偶数的回文串
for(int i=0;i<len;i++){//枚举中心位置
int left=i,right=i+1;//以i为中心向左右两边扩展
while(left>=0 && right<len && str.at(left)==str.at(right)){
if(right-left+1>maxlen){
start=left;//更新回文串起始位置
maxlen=right-left+1;//更新回文串长度
}
left--;
right++;
}
}
str=str.substr(start, maxlen);
}
int main(){
cin>>str;
longestPalindrome();
cout <<str<<endl;
return 0;
}
【动态规划】
设 dp[j][i] 表示从 j 到 i 的子串是否是回文串,则:
当 dp[j][i]=true 时,表示从 j 到 i 的子串为回文子串,且子串起点位置为 j,长度为 i - j + 1
时间复杂度为:O(N ^ 2)
string str;
bool dp[N][N];
void longestPalindrome(){
memset(dp,false,sizeof(dp));
int len=str.size();//字符串长度
int start=0;//最长回文子串起点
int maxlen=1;//最长回文子串长度
for(int i=0;i<len;i++){//字符串终点
for(int j=0;j<=i;j++){//字符串起点
if(i-j<2)
dp[j][i]=(str[i]==str[j]);
else
dp[j][i]=(str[i]==str[j] && dp[j+1][i-1]);
if(dp[j][i] && maxlen<i-j+1){
start=j;//更新回文串起点
maxlen=i-j+1;//更新回文串长度
}
}
}
str=str.substr(start, maxlen);
}
int main(){
cin>>str;
longestPalindrome();
cout<<str<<endl;
return 0;
}
【Manacher 算法】
时间复杂度:O(N)
算法详解:点击这里