给你一个字符串 s,找到 s 中最长的回文子串
示例:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案
输入:s = "cbbd"
输出:"bb"
看到题目的第一个想法就是用栈来实现。但是栈碰上奇数个的时候,怎么解决该不该弹出。还有栈什么时候弹出。比如abbabba。想了一阵没有解决的办法。
只好蛮力法,俩个指针输出所有的(比现在最长回文串还长的)串,再调用判断是不是回文。如果是回文,就记录下最大那个。时间复杂度太高了O(n3)。
(0).蛮力法
//蛮力法:输出所有的字符串,检查它是不是回文
class Solution {
public:
string longestPalindrome(string s) {
if(s.length() < 2)
return s;
int begin = 0,maxsize = 1;
for(int i = 0;i < s.length()-1;i++){
for(int j = i + 1;j < s.length();j++){
if((j-i+1)> maxsize && isabcba(s,i,j)){
begin = i;
maxsize = j-i+1;
}
}
}
return s.substr(begin,maxsize);
}
bool isabcba(string s,int start,int end){
while(end > start){
if(s[start] != s[end])
return false;
start++;
end--;
}
return true;
}
};
太丢人了,我这个代码在leetcode中的一个例程中超过leetcode的时间限制了。
看看官方的答案吧。
(1).中心扩散O(n2)
class Solution {
public:
pair<int, int> expandAroundCenter(const string& s, int left, int right) {
while (left >= 0 && right < s.size() && s[left] == s[right]) {
--left;
++right;
}
return {left + 1, right - 1};
}
string longestPalindrome(string s) {
int start = 0, end = 0;
for (int i = 0; i < s.size(); ++i) {
auto [left1, right1] = expandAroundCenter(s, i, i);
auto [left2, right2] = expandAroundCenter(s, i, i + 1);
if (right1 - left1 > end - start) {
start = left1;
end = right1;
}
if (right2 - left2 > end - start) {
start = left2;
end = right2;
}
}
return s.substr(start, end - start + 1);
}
};
遍历每一个点,左右扩展到最大,找到最大的回文。奇扩展,偶扩展各一遍。官方直接用left,right遍历。我自己写的就麻烦多了。
(2).动态规划O(n2)
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n));
string ans;
for (int l = 0; l < n; ++l) {
for (int i = 0; i + l < n; ++i) {
int j = i + l;
if (l == 0) {
dp[i][j] = 1;
} else if (l == 1) {
dp[i][j] = (s[i] == s[j]);
} else {
dp[i][j] = (s[i] == s[j] && dp[i + 1][j - 1]);
}
if (dp[i][j] && l + 1 > ans.size()) {
ans = s.substr(i, l + 1);
}
}
}
return ans;
}
};
动态规划只是改变了查找的时候的速率,用表格存下dp[i+1][j-1]是不是回文,是的话判断s[i]和s[j]是否相等。
(3).manacher算法O(n)(面试不要求)
这个算法看的我头大。
class Solution {
public:
int expand(const string& s, int left, int right) {
while (left >= 0 && right < s.size() && s[left] == s[right]) {
--left;
++right;
}
return (right - left - 2) / 2;
}
string longestPalindrome(string s) {
int start = 0, end = -1;
string t = "#";
for (char c: s) {
t += c;
t += '#';
}
t += '#';
s = t;
vector<int> arm_len;
int right = -1, j = -1;
for (int i = 0; i < s.size(); ++i) {
int cur_arm_len;
if (right >= i) {
int i_sym = j * 2 - i;
int min_arm_len = min(arm_len[i_sym], right - i);
cur_arm_len = expand(s, i - min_arm_len, i + min_arm_len);
} else {
cur_arm_len = expand(s, i, i);
}
arm_len.push_back(cur_arm_len);
if (i + cur_arm_len > right) {
j = i;
right = i + cur_arm_len;
}
if (cur_arm_len * 2 + 1 > end - start) {
start = i - cur_arm_len;
end = i + cur_arm_len;
}
}
string ans;
for (int i = start; i <= end; ++i) {
if (s[i] != '#') {
ans += s[i];
}
}
return ans;
}
};