Leetcode C++《热题 Hot 100-24》5.最长回文子串
- 题目
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路
- 方案1:采用动态规划, dp的值表示是否为回文子串,或者子串长度均可,时间复杂度和空间复杂度都是n*n
- if s[i] == s[j], dp[i][j] = dp[i-1][j+1]
- 方案2:基于方案1,想出了中心扩展法,任何一个字符都有可能处于回文子串的中心,根据该字符向两边扩展,时间复杂度为n*n,空间复杂度为O(1)
- 方案3:
- 据说有一个方案manacher时间复杂度和空间复杂度都是n,必须学习实现:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-bao-gu/。
- 利用回文串的对称性:C 和 R 所对应的回文串是当前循环中 R 最靠右的回文串。
- 也可以参考这个链接https://www.cnblogs.com/grandyang/p/4475985.html 太难理解了,哭泣,有图看会好理解一点点。
- 代码
class Solution {
public:
//方案3
string longestPalindrome(string s) {
string str = addSomeChar(s);
int c = 0, r = 0, maxLen=0, maxC=0;
vector<int> p;
for (int i = 0; i < str.length(); i++) {
p.push_back(0);
}
for (int i = 1; i < str.length(); i++) {
int other_i = 2 * c - i;
if (other_i >=0 && r > other_i) {
p[i] = min (r - i, p[other_i]); //利用回文字符串的对称性hh
} else {
p[i] = 1; //因为两边有#
}
while(str[i-p[i]]==str[i+p[i]]) {
p[i]++; //这个太妙了,而且i也不用动
}
if (i+p[i] > r) {
c = i;
r = i+p[i];
if (maxLen < p[i]) {
maxLen = p[i];
maxC = i;
}
}
}
return s.substr((maxC-p[maxC])/2, p[maxC]-1);
}
string addSomeChar(string s) {
string res = "^";
for (int i = 0; i < s.length(); i++) {
res += "#";
res += s[i];
}
res += "#$";
return res;
}
//方案2:
/*string longestPalindrome(string s) {
if (s == "")
return "";
int maxLength = 1;
int maxLeft = 0;
int maxRight = 0;
for (int i = 0; i < s.length(); i++) {
//假设最大回文子串包含s[i],首先把连续的相同的字符聚集在一起
int left = i, right = i;
for (int j = i+1; j < s.length(); j++) {
if (s[j] != s[i]) {
right = j-1;
break;
} else
right++;
}
for (int j = i-1; j >= 0; j--) {
if (s[j] != s[i]) {
left = j+1;
break;
} else
left--;
}
//cout << s[i] << " " << left << " " << right << " " << endl;
int add = 0;
for (int j = 0; j < s.length()-right-1; j++) {
//cout << "&&&&& " << j << endl;
if ((left-1-j) < 0) {
//cout << "&&&&&11 " << j << endl;
break;
}
if (s[right+1+j] != s[left-1-j]) {
left = left-j;
right = right+j;
add = 0;
//cout << "&&&&&22 " << j << endl;
break;
} else {
add++;
//cout << "&&&&&33 " << j << endl;
}
}
if (add != 0) {
left = left - add;
right = right + add;
}
if ((right-left+1) > maxLength) {
maxLength = right-left+1;
maxLeft = left;
maxRight = right;
}
//cout << s[i] << " " << s.substr(left, right-left+1) << endl;
}
return s.substr(maxLeft, maxLength);
}*/
};