description:
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example:
Example 1:Input: "babad"Output: "bab"Note: "aba" is also a valid answer.Example 2:Input: "cbbd"Output: "bb"
my answer:
解法一:比较简单的想法就是一个字符串从头开始遍历,对于每个字符都分别向两边走,左边和右边一样就走一步,一直到不一样了,那就是对于中间这个字符就已经是最大回文长度了,和之前的最大比一下,之后进行下一个字符,所以时间复杂度是n^2。然后还有两个特殊的case,第一个是字串本身小于3的话,那一定是回文的,还有就是遍历的时候,假设说当前最大长度是7,现在遍历到倒数第三个字符了,也就是说就算是它右边的俩和它左边俩一样的就是回文它最长也就是5了,所以当剩余n-i < maxlength/2的时候就停了。
下面两个答案,上边是我的,底下是大佬的,md就是一样的嘛,无fuck可说,我的就是一直一直runtimeerror【微笑】。// class Solution {// public:// string longestPalindrome(string s) {// if (s.size() < 2) return s;// int n = s.size(), maxlength = 0, start = 0;// for (int i = 0; i < n; ){// if(n - i <= maxlength / 2) break;// int left =i, right = i;// while(s[right] == s[right + 1] && right < n - 1) ++right;// i = right + 1;// while(s[left - 1] == s[right + 1] && right < n - 1 && left > 0){// --left;// ++right;// }// // maxlength = max(maxlength, right - left + 1); // // start = left;// if (maxlength < right - left + 1) {// maxlength = right - left + 1;// start = left;// }// }// return s.substr(start, maxlength);// }// };class Solution {public: string longestPalindrome(string s) { if (s.size() < 2) return s; int n = s.size(), maxLen = 0, start = 0; for (int i = 0; i < n;) { if (n - i <= maxLen / 2) break; int left = i, right = i; while (right < n - 1 && s[right + 1] == s[right]) ++right; i = right + 1; while (right < n - 1 && left > 0 && s[right + 1] == s[left - 1]) { ++right; --left; } if (maxLen < right - left + 1) { maxLen = right - left + 1; start = left; } } return s.substr(start, maxLen); }};
方法二:
卧槽真的太难了,这个算法叫做manacher算法,哪位大佬翻译成马拉车了... 算法还可以,就是在为什么是线性这个问题上想了好久好久,所以为什么呢?之前的就上面那个方法一暴力对每个元素处理,且每个元素都相当于是对所有存在的元素来一次比较所以是n^2,而manacher算法之所以是线性的,是因为他利用里之前的结果,就是之前的元素已经遍历过的他就不会再遍历了,你走一轮就会发现他走的检查的元素都是他右边那些到现在为止程序从来未涉及过的无污染元素,所以因为不重复才会是线性,也是大佬们说马拉车算法的精华就在这一句p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
下面扔上全代码:
#include#include #include using namespace std;string Manacher(string s) { // Insert '#' string t = "$#"; for (int i = 0; i < s.size(); ++i) { t += s[i]; t += "#"; } // Process t vector p(t.size(), 0); int mx = 0, id = 0, resLen = 0, resCenter = 0; for (int i = 1; i < t.size(); ++i) { p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1; while (t[i + p[i]] == t[i - p[i]]) ++p[i]; if (mx < i + p[i]) { mx = i + p[i]; id = i; } if (resLen < p[i]) { resLen = p[i]; resCenter = i; } } return s.substr((resCenter - resLen) / 2, resLen - 1);}int main() { string s1 = "12212"; cout << Manacher(s1) << endl; string s2 = "122122"; cout << Manacher(s2) << endl; string s = "waabwswfd"; cout << Manacher(s) << endl;}
其实主要大体思路还是针对每一个元素去看它两边一样不一样,只不过是不是从它跟前紧第一个开始了,是从确认回文半径+1处开始检查。