一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
题目描述
给定一个仅包含小写字母的字符串,求它的最长回文子串的长度。
所谓回文串,指左右对称的字符串。
所谓子串,指一个字符串删掉其部分前缀和后缀(也可以不删)的字符串
数据范围:字符串长度1≤s≤350
进阶:时间复杂度:O(n) ,空间复杂度:O(n)
输入描述:
输入一个仅包含小写字母的字符串
输出描述:
返回最长回文子串的长度
示例1
输入:
cdabbacc
输出:
4
说明:
abba为最长的回文子串
解题思路
采用中心扩展法:枚举所有的回文中心并尝试向两边扩展,直到无法扩展为止。此时的回文子串长度即为此回文中心下的最长回文串长度,即可得到最终的答案。但字符子串需要分奇数和偶数字符串,两种情况来考虑,例如:aba,abba。时间复杂度为O(n^2),双重循环,n为字符串长度,空间复杂度为O(1)。
中心扩展法
#include<bits/stdc++.h>
using namespace std;
int main()
{
string str;
while(cin>>str){
if(str.size()==1)
return 1;
int len=str.size();
int count=1;//定义回文子串的长度
for(int i=0;i<len;++i){//循环遍历字符串
int j=i,k=i+1;//当字符串为偶数时
while(j>=0 && k<len && str[j]==str[k]){
if(k-j+1>count) count=k-j+1;
j--;
k++;
}
}
for(int i=0;i<len;++i){
int j=i-1,k=i+1;//当字符串为奇数时
while(j>=0 && k<len && str[j]==str[k]){
if(k-j+1>count) count=k-j+1;
j--;
k++;
}
}
cout<<count<<endl;
}
`}`
本题也可以采用暴力解法和动态规划来解决。暴力解法是可以考虑直接枚举所有可能出现的开头的位置和所有可能出现的结尾的位置,然后我们每次对这样的一个字符串进行一个判断是否是回文字符串,如果是的话,我们时刻更新我们的最长的回文子串的一个长度,然后最后输出。采用暴力解法会涉及到三层循环,所以时间复杂度为O(n^3),空间复杂度为O(1),只引用了常数级别的空间。
动态规划
#include <bits/stdc++.h>
using namespace std;
int main() {
string str;
while(cin>>str){
int n = str.size();
int maxlen = -1;
vector<vector<bool>> v(n,vector<bool>(n,false));
for(int i = 0 ;i<n;i++){//这里赋值边界条件其实还应该判断输入是否是1个字符或者两个,这里没判断,样例没有给这种例子,可以AC
v[i][i] = true;
}
for(int i = 0 ;i<n-1;i++){
if(str[i]==str[i+1]){
v[i][i+1]=true;
maxlen=2;
}
}
for(int i = 2;i<n;i++){
for(int j =0;j<i-1;j++){
if(str[i]==str[j]){
v[j][i]=v[j+1][i-1];
}
if(v[j][i]&&(i-j+1)>maxlen) maxlen=i-j+1;//这判断最大长度超过没
}
}
cout<<maxlen<<endl;
}
}