![](https://cdn.jsdelivr.net/gh/xiaok0707/MyPhotos@master/img/20200820193348.png)
区间DP
dp[i][j]
表示子串 s[i...j]
是否是回文串,有如下递推式.
d
p
[
i
]
[
j
]
=
d
p
[
i
+
1
]
[
j
−
1
]
a
n
d
s
[
i
]
=
s
[
j
]
dp[i][j]=dp[i+1][j-1] \ and \ s[i]=s[j]
dp[i][j]=dp[i+1][j−1] and s[i]=s[j]
即如果 s[i+1...j-1]
是一个回文串,同时 s[i]==s[j]
,则 s[i...j]
也是一个回文串,初始化所有的 dp[i][i]
和 dp[i][i+1]
,然后根据公式递推求解.
时间、空间复杂度均为 O ( n 2 ) O(n^2) O(n2).
class Solution {
public:
static const int N=1050;
bool dp[N][N];//dp[i][j]表示s[i...j]是否为回文串
string longestPalindrome(string s) {
int n=s.length();
for(int i=0;i<n;++i) dp[i][i]=true;
for(int i=0;i+1<n;++i) dp[i][i+1]=s[i]==s[i+1];
for(int len=2;len<n;++len){
for(int i=0;i+len<n;++i){
int j=i+len;
if(dp[i+1][j-1] && s[i]==s[j]) dp[i][j]=true;
else dp[i][j]=false;
}
}
int le,ri,mx=0;
for(int i=0;i<n;++i){
for(int j=i;j<n;++j){
if(dp[i][j] && j-i+1>mx){
mx=j-i+1;
le=i;
ri=j;
}
}
}
string ans="";
for(int i=le;i<=ri;++i) ans+=s[i];
return ans;
}
};
中心扩展
区间DP的方法中,初始状态也就是边界状态为长度为 1 的子串和长度为 2 的子串,我们可以枚举所有的初始状态,然后从初始状态开始,不断向左右两边扩展,直到当前的字符串不再是回文串为止,后续的子串也不可能是回文串了.
时间复杂度依然是 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( 1 ) O(1) O(1).
class Solution {
public:
string longestPalindrome(string s) {
int len=s.length();
int mx=0,le,ri;
for(int i=0;i<len;++i){
int j=1;
while(i-j>=0 && i+j<len && s[i-j]==s[i+j]) ++j;
if(2*j-1>mx){
mx=2*j-1;
le=i-j+1;
ri=i+j-1;
}
j=0;
while(i-j>=0 && i+j+1<len && s[i-j]==s[i+j+1]) ++j;
if(2*j>mx){
mx=2*j;
le=i-j+1;
ri=i+j;
}
}
string ans=s.substr(le,ri-le+1);
return ans;
}
};
Manacher
使用 Manacher 算法可以快速求出以每个字符为中心,最大回文子串的长度. 时间、空间复杂度均为 O ( n ) O(n) O(n).
算法细节见 Manacher算法详解
class Solution {
public:
int p[1005<<1];
string init(string s){
string res="#";
for(char ch:s){
res+=ch;
res+='#';
}
return res;
}
void manacher(string s){
int len=s.length();
int id=0,mx=0;
for(int i=0;i<len;++i){
p[i]=i<mx?min(p[2*id-i],mx-i):1;
while(i-p[i]>=0 && i+p[i]<len && s[i+p[i]]==s[i-p[i]]) ++p[i];
if(i+p[i]>mx){
mx=i+p[i];
id=i;
}
}
}
string longestPalindrome(string s) {
string str=init(s);
manacher(str);
int id,mx=0;
for(int i=0;i<(int)str.length();++i){
if(p[i]>mx){
mx=p[i];
id=i;
}
}
string ans="";
for(int i=id-p[id]+1;i<id+p[id];++i){
if(str[i]!='#') ans+=str[i];
}
return ans;
}
};
个人 LeetCode 代码仓库地址:MyLeetCode,记录刷题成长之路,欢迎各位小伙伴们多多 star ~