给定一个字符串 s s s,找到 s s s 中最长的回文子串。你可以假设 s s s 的最大长度为 1000 1000 1000。
示例 1 1 1:
输入: “
b
a
b
a
d
babad
babad”
输出: “
b
a
b
bab
bab”
注意: “
a
b
a
aba
aba” 也是一个有效答案。
示例
2
2
2:
输入: “
c
b
b
d
cbbd
cbbd”
输出: “
b
b
bb
bb”
思路:
1)中心扩展算法。举个很简单的例子,字符串" a b a aba aba“是一个回文串,那么两边加上一个 x x x字符,即字符串为” x a b a x xabax xabax",那肯定也为回文串。那么这道题就可以这样解决,我们遍历字符串,将每个字符当作一个回文子串的中心点,向两边扩展,由于回文子串的长度可能为奇数也可能为偶数,则扩展方式就有两种,一种为奇数时的 ( i , i ) (i,i) (i,i)扩展,另一种为偶数时的 ( i , i + 1 ) (i,i+1) (i,i+1)扩展,判断两种方式扩展的长度大小,大的作为以该字符为中心点的回文子串的最大长度
class Solution {
public:
string longestPalindrome(string s) {
int length = s.size();
if (length < 1)
return "";
int start = 0, end = 0;
for (int i = 0; i < length; ++i) {
int len1 = expandAroundCenter(s, i, i); //奇数扩展
int len2 = expandAroundCenter(s, i, i + 1); //偶数扩展
int len = max(len1, len2); //比较两种方式扩展的最大长度
//更新最大长度及回文子串的起始与结束
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substr(start, end - start + 1);
}
//向两边扩展
int expandAroundCenter(string s, int left, int right) {
while (left >= 0 && right < s.size() && s[left] == s[right]) {
left--;
right++;
}
return right - left - 1;
}
};
2)动态规划方法。 d p [ i ] [ j ] = 1 dp[i][j] = 1 dp[i][j]=1表示 i − j i-j i−j为回文子串,然后可以得到以下的状态转移方程:
- d p [ i ] [ i ] = 1 dp[i][i] = 1 dp[i][i]=1,其本身字符当然为一个回文串
- d p [ i ] [ i + 1 ] = 1 dp[i][i + 1] = 1 dp[i][i+1]=1, s [ i ] = = s [ i + 1 ] s[i] == s[i + 1] s[i]==s[i+1] && i < n i < n i<n
- d p [ i ] [ i + l e n ] = d p [ i + 1 ] [ i + l e n − 1 ] dp[i][i + len] = dp[i + 1][i + len - 1] dp[i][i+len]=dp[i+1][i+len−1], s [ i ] = = s [ i + l e n ] s[i] == s[i + len] s[i]==s[i+len] && i + l e n < n i + len < n i+len<n,即" x S x xSx xSx"是否为回文串依赖于 S S S是否为回文串
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
if (n < 2)
return s;
int start = 0, tlen = 1;
int dp[n][n];
memset(dp, 0, sizeof(dp));
//初始化
for (int i = 0; i < n; ++i) {
dp[i][i] = 1; //本身为回文串
//满足条件相邻字符相等也为回文串
if (i + 1 < n && s[i] == s[i + 1]) {
tlen = 2;
start = i;
dp[i][i + 1] = 1;
}
}
//从长度遍历,扩展回文串
for (int len = 2; len < n; ++len) {
for (int i = 0; i < n; ++i) {
if (i + len < n && s[i] == s[i + len]) {
dp[i][i + len] = dp[i + 1][i + len - 1];
if (dp[i][i + len] && len + 1 > tlen) {
tlen = len + 1;
start = i;
}
}
}
}
return s.substr(start, tlen);
}
};