最长回文子串
最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解法 4: 扩展中心
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
class Solution {
public:
string myStr;
Solution(string str) : myStr(str) {};
string longestPalindrome() {
cout << "myStr: " << myStr << endl;
if ( myStr.empty() ) cout << "empty" << endl;
int start = 0, end= 0;
for (int i = 0; i < myStr.size(); ++i) {
int len1 = expandAroundCenter(myStr, i, i);
int len2 = expandAroundCenter(myStr, i, i + 1);
int len = max(len1, len2);
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len /2;
}
}
string result;
for (int i = start; i <= end; ++i) {
result += myStr[i];
}
return result;
}
int expandAroundCenter(string s, int left, int right) {
int L = left, R = right;
while (L >= 0 && R < s.size() && s.at(L) == s.at(R)) {
--L;
++R;
}
return R - L -1;
}
};
int main() {
string str1;
cout << "intput str1: " << endl;
cin >> str1;
Solution sl1(str1);
string result = sl1.longestPalindrome();
cout << "result: " << result << endl;
}
解法 5: Manacher’s Algorithm 马拉车算法。
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
class Solution {
public:
string Str;
Solution(string str) : Str(str) {};
// 马拉车算法
string longestPalindrome() {
cout << "Str: " << Str << endl;
string myStr = preProcess(Str);
cout << "myStr: " << myStr << endl;
int n = myStr.size();
vector<int> P(n,0);
int C = 0, R = 0; //center, edge Of right
int maxLen = 0, centerIndex =0;
for (int i = 1; i < n -1; ++i) {
int i_mirror = 2 * C - i;
cout << "i: " << i << " ";
cout << "i_mirror: " << i_mirror << endl;
//P[i] = R > i ? min(R - i, P[i_mirror]) : 0;
if (i < R) {
//P[i] = min(R - i, P.at(i_mirror));
if(P.at(i_mirror) < R-i) {
P.at(i) = P.at(i_mirror);
} else {
P.at(i) = R -i;
}
} else {
P.at(i) = 0;
}
cout << "P.at(" << i << "):" << P[i] << endl;
// 碰到之前讲的三种情况时候,需要利用中心扩展法
while(myStr.at(i - P[i] -1) == myStr.at(i + P[i] +1)) { //not longest
++P[i];
}
// 判断是否需要更新 R
if (R < i + P[i]) { //edge Of right over R
C = i;
R = i + P[i];
}
if (maxLen < P[i]) {
maxLen = P[i];
centerIndex = i;
}
}
int start = (centerIndex - maxLen) / 2;
return Str.substr(start,start + maxLen);
}
private:
string preProcess(string s) {
if (s.empty()) {
cout << "empty: " << endl;
return "^$";
}
string ret("^");
for (auto& elem : s) {
ret += "#";
ret += elem;
}
ret += "$";
return ret;
}
};
string preProcess(string s);
int main() {
string str1("baba");
cout << "Input a string" << endl;
cin >> str1;
Solution sl1(str1);
string result = sl1.longestPalindrome();
cout << "result: " << result << endl;
}
参考说明 https://www.cnblogs.com/love-yh/p/7072161.html
引用参考原作者:
昵称: BraveWg
三)如何求数组P [ ]
从左往右计算数组P[ ], Mi为之前取得最大回文串的中心位置,而R是最大回文串能到达的最右端的值。
1)当 i <=R时,如何计算 P[ i ]的值了?毫无疑问的是数组P中点 i 之前点对应的值都已经计算出来了。利用回文串的特性,我们找到点 i 关于 Mi 的对称点 j ,其值为 j= 2*Mi-i 。因,点 j 、i 在以Mi 为中心的最大回文串的范围内([L ,R]),
a)那么如果P[j] <R-i (同样是L和j 之间的距离),说明,以点 j 为中心的回文串没有超出范围[L ,R],由回文串的特性可知,从左右两端向Mi遍历,两端对应的字符都是相等的。所以P[ j ]=P[ i ](这里得先从点j转到点i 的情况),如下图:
b)如果P[ j ]>=R-i (即 j 为中心的回文串的最左端超过 L),如下图所示。即,以点 j为中心的最大回文串的范围已经超出了范围[L ,R] ,这种情况,等式P[ j ]=P[ i ]还成立吗?显然不总是成立的!因,以点 j 为中心的回文串的最左端超过L,那么在[ L, j ]之间的字符肯定能在( j, Mi ]找到相等的,由回文串的特性可知,P[ i ] 至少等于R- i,至于是否大于R-i(图中红色的部分),我们还要从R+1开始一一的匹配,直达失配为止,从而更新R和对应的Mi以及P[ i ]。
2)当 i > R时,如下图。这种情况,没法利用到回文串的特性,只能老老实实的一步步去匹配。
上一篇: 最长回文子串