题目描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
思路
1.暴力法
时间复杂度:O(n^3)(每一轮都是n+到1,类同n ^2,一共需要n轮,故为n ^3)
空间复杂度:O(1)
见代码
class Solution {
//暴力法
public:
string longestPalindrome(string s) {
int max=0;
string ans="";
for(int i=0;i<s.length();++i)
for(int j=i;j<s.length();++j)
//i为起始位置,j为结尾位置,因为1个字符也为回文串,故结尾位置从i开始
{//判断该子串是否为回文串
int begin=i,end=j;
while(begin<end&&s[begin]==s[end])
{//若相同,则不断向中间靠近
begin++;end--;
}
//若为回文串,奇数时,end==begin,偶数时begin>end
if(begin>=end&&max<j-i+1)
{
max=j-i+1;
ans=s.substr(i,j-i+1);
}
}
return ans;
}
};
2.动态规划法
时间复杂度为O(n^2)
空间复杂度为O(n^2)
class Solution {
//动态规划法
public:
string longestPalindrome(string s) {
int max=0;
int start=0;//记录最大子串起始位置
int n=s.length();
if(n==0)
return "";
bool dp[n][n];
memset(dp, 0, sizeof(dp));
for(int j=0;j<n;++j)
for(int i=0;i<=j;++i)
//i为起始位置,j为结尾位置,因为1个字符也为回文串,故结尾位置从i开始
{
//当为单个或两个字符时,判断s[i]==s[j]是否成立,即可判断是否为回文串
if(j-i<=1)
dp[i][j]=(s[i]==s[j]);
else
{
//若大于两个字符,则若d[i+1][j-1]为ture
//且s[i]==s[j] 则说明s(i,j)也为回文串
dp[i][j]=dp[i+1][j-1]&&(s[i]==s[j]);
}
if(dp[i][j]&&j-i+1>max)
{//更新最大值
max=j-i+1;
start=i;
}
}
return s.substr(start,max);
}
};
3.中心扩展算法
即从中间,向两端扩展,判断是否为回文段
对字符串的每个位置都判断一次
总共要判断n次,扩展的时候也会遍历次字符串
故时间复杂度为O(n^2),空间复杂度为O(1)
class Solution {
//中心扩展算法
public:
string longestPalindrome(string s) {
int max=0;
int start=0;//记录最大子串起始位置
int n=s.length();
if(n==0)
return "";
for(int i=0;i<n;++i)
{
int l1=matchLen(s,i,i);//以i为中心的奇数个字符
int l2=matchLen(s,i,i+1);//以i,i+1为中心的偶数个字符
int len=l1>l2?l1:l2;
if(len>max)
{
max=len;
if(len&1==1)//奇数
start=i-len/2;
else //偶数
start=i-len/2+1;
}
}
return s.substr(start,max);
}
private:
int matchLen(string s,int i,int j)
{//判断以i,j为中心的字符串是否回文
//i为起始位置,j为结尾位置,判断s[i]==s[j]是否成立,若成立则扩展到i-1,j+1
if(j-i==1&&s[i]!=s[j])//若为两个不同的字符,则特殊判断
return 1;
while(i>=0&&j<s.length()&&s[i]==s[j])
{
--i;
++j;
}
return j-i-1;//j与i已经发生改变,故为-1
}
};
4.Manacher 算法
Manacher算法的时间复杂度为O(N),(运用已有的信息和对称)具体可参考:
https://www.cnblogs.com/grandyang/p/4475985.html