给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba"
也是一个有效答案。
示例 2:
输入:"cbbd"
输出: "bb"
这题求最长回文子串,有三种方法可以采用,最简单的是用动态规划,时间复杂度是O( n2 n 2 ),另外一种是中心扩展,第三种方法是称为马拉车的算法。
动态规划需要开一个二维数组,DP[i][j]=s[i]==s[j]&&DP[i+1][j-1],时间复杂度较高
代码:
class Solution {
public:
string longestPalindrome(string s) {
int len=s.size();
vector<vector<int>> flag(len,vector<int>(len,0));
int maxres=0,idx=0;
for(int i=0;ifor(int j=0,k=i;jif(k==j) flag[j][k]=1;
else if(s[k]==s[j]&&j+1==k) flag[j][k]=2;
else if(s[k]==s[j]&&flag[j+1][k-1]>0) flag[j][k]=flag[j+1][k-1]+2;
else flag[j][k]=0;
if(flag[j][k]>maxres){
maxres=flag[j][k];
idx=j;
}
}
}
return s.substr(idx,maxres);
}
};
这种做法主要是考虑基于一个点为中心,然后左右两边扩展,得出以该点为中心的最长回文串。但是需要注意的是回文串长度是奇数和偶数,有所差别需要都考虑。
时间复杂度高于上一种方法
代码:
//加快代码运行速度
static const auto __ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size(),pos=-1,maxlen=0;
for(int i=0;iint r=1;
while(i-r>=0&&i+rif(maxlen<2*r-1){
pos=i-r+1;
maxlen=2*r-1;
}
if(i>=n||s[i]!=s[i+1]) continue;
r=1;
while(i-1>=0&&i+1+r1+r]) r++;
if(maxlen<2*r){
pos=i-r+1;
maxlen=2*r;
}
}
return s.substr(pos,maxlen);
}
};
马拉车算法可以实现近似O(n)求解,具体原理见马拉车算法
代码:
//加快代码运行速度
static const auto __ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
string longestPalindrome(string s) {
int ns=s.size(),n=2*ns+1;
vector<char> str(n,'*');
vector<int> slen(n,0);
for(int i=0;i2*i+1]=s[i];
int curpos=0,curlen=0,maxpos=0,maxr=0;
for(int i=0;iint mi=2*curpos-i,r=slen[mi];
if(i+rcontinue;
}
r=curpos+curlen-i;
while(i-r>=0&&i+rif(maxrif(i+maxr>=n) break;
}
return s.substr(maxpos/2-maxr/2,maxr);
}
};