最长回文子串
最长回文子串
题目描述:
给你一个字符串
s
,找到s
中最长的回文子串
示例1:
输入:s = “babad”
输出:“bab”
示例2:
输入:s = ”cbbd“
输出:“bb”
tips:
1 <= s.length <= 100
s仅由数字和英文字母组成
题解:
方法一:动态规划
对于回文串s,在s左右两边加上相同的字符得到s‘,则s’仍然为回文串,由此可以建立转移方程:
\[if(s[i] == s[j]\ \&\& \ s[i + 1......j - 1] \ is \ pal) \\
dp[i][j] = dp[i + 1][j - 1] + 2
\]
其中\(dp[i][j]\)代表i到j间是否是一个回文串,是则记录长度,不是为0。
处理边界
当字符串长度为1时,必为回文串\(\rightarrow \ dp[i][i] = 1\)
当字符串长度为2且两字符相同时,必为回文串\(s[i] = s[i + 1] \ \rightarrow \ dp[i][i + 1] = 2\)
class Solution {
public:
string longestPalindrome(string s) {
int n = s.length();
if(n < 2) return s;
vector<vector<int>> dp(n, vector<int>(n));
int ans = 1, be = 0;
for(int i = 0; i < n; ++i) dp[i][i] = 1;
for(int l = 2; l <= n; ++l) {
for(int i = 0; i < n; ++i) {
int j = i + l - 1;
if(j >= n) break;
if(s[i] != s[j]) dp[i][j] = 0;
else {
if(l == 2) {
dp[i][j] = 2;
}
else {
if(dp[i + 1][j - 1]) dp[i][j] = dp[i + 1][j - 1] + 2;
}
if(dp[i][j] > ans) {
ans = dp[i][j];
be = i;
}
}
}
}
return s.substr(be, ans);
}
};
方法二:中心扩展法
从方法一状态转移方程可以看出,每次回文子串长度增加情况唯一:
\(dp[i][j] + 2 \leftarrow dp[i + 1][j - 1] \leftarrow ....边界情况\)
从边界情况开始扩展,最后也可以得到最长回文子串。
class Solution {
public:
string longestPalindrome(string s) {
int be = 0, maxLen = 1;
int n = s.length();
for(int i = 0; i < n; ++i) {
int l = i, r = i;
int len = -1;
while(l >= 0 && r < n && s[l] == s[r]) {
len += 2;
l--;
r++;
}
if(len > maxLen) {
maxLen = len;
be = l + 1;
}
len = 0;
l = i, r = i + 1;
while(l >= 0 && r < n && s[l] == s[r]) {
len += 2;
l--; r++;
}
if(len > maxLen) {
maxLen = len;
be = l + 1;
}
}
return s.substr(be, maxLen);
}
};
方法三:Manancher(马拉车算法)
-------------待更----------------