5. Longest Palindromic Substring
- 中心点扩张
- Manacher 算法
题目
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example:
Input: “babad”
Output: “bab”
Note: “aba” is also a valid answer.
Example:
Input: “cbbd”
Output: “bb”
思路
- 中心点扩张:通过确定中心点,向外扩张寻找回文子串。
- 复杂性分析:
- 时间复杂度:O(n^2).
- 空间复杂度:O(n).
题解
class Solution {
public:
string longestPalindrome(string s) {
int len = s.size();
if (!len) return "";
if (len == 1) return s;
string ans;
int templen = 0;
int begin = 0, end = 1;
for (int i = 1; i < len; i++) {
// "abba"式的偶数回文遍历
begin = i -1;
end = i;
while (begin > -1 && end < len && s[begin] == s[end]) {
begin--;
end++;
}
templen = end - begin - 1;
if (templen > ans.size()) ans = s.substr(begin+1, templen);
// "abcba"式的奇数回文遍历
begin = i - 1;
end = i + 1;
while (begin > -1 && end < len && s[begin] == s[end]) {
begin--;
end++;
}
templen = end - begin - 1;
if (templen > ans.size()) ans = s.substr(begin+1, templen);
}
return ans;
}
};
优化
思路
Manacher 算法:通过在字母间插入特殊字符“#”来将输入字符串 S 变为另一字符串 T。这种方式不仅将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度,而且可以消除上一个算法对重叠回文的重复计算,将时间复杂度降至O(n)。
代码
class Solution {
public:
// Transform S into T.
// For example, S = "abba", T = "^#a#b#b#a#$".
// ^ and $ signs are sentinels appended to each end to avoid bounds checking
string preProcess(string s) {
int n = s.length();
if (n == 0) return "^$";
string ret = "^";
for (int i = 0; i < n; i++)
ret += "#" + s.substr(i, 1);
ret += "#$";
return ret;
}
string longestPalindrome(string s) {
string T = preProcess(s);
int n = T.length();
int *P = new int[n];
int C = 0, R = 0;
for (int i = 1; i < n-1; i++) {
int i_mirror = 2*C-i; // equals to i' = C - (i-C)
P[i] = (R > i) ? min(R-i, P[i_mirror]) : 0;
// Attempt to expand palindrome centered at i
while (T[i + 1 + P[i]] == T[i - 1 - P[i]])
P[i]++;
// If palindrome centered at i expand past R,
// adjust center based on expanded palindrome.
if (i + P[i] > R) {
C = i;
R = i + P[i];
}
}
// Find the maximum element in P.
int maxLen = 0;
int centerIndex = 0;
for (int i = 1; i < n-1; i++) {
if (P[i] > maxLen) {
maxLen = P[i];
centerIndex = i;
}
}
delete[] P;
return s.substr((centerIndex - 1 - maxLen)/2, maxLen);
}
};
反思
- 奇偶回文串。
进行中心点向外扩张回文判断时,需要同时考虑奇数回文串和偶数回文串的情况。 - Manacher 算法要点。
if P[ i’ ] ≤ R – i,
then P[ i ] ← P[ i’ ]
else P[ i ] ≥ P[ i’ ]. (Which we have to expand past the right edge (R) to find P[ i ].