LeetCode Longest Palindromic Substring
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
class Solution { private: const char sep_char = '\1'; public: string longestPalindrome(string s) { int max_len = 0; int len = s.length(); if (len <= 1) return s; string str; str.push_back(sep_char); for (int i=0; i<len; i++) { str.push_back(s[i]); str.push_back(sep_char); } int nlen = 2 * len + 1; vector<int> P(nlen, 0); int last_i = 0; int last_r = 0; int maxv = -1; int maxi = -1; for (int i=0; i<nlen; i++) { int p = i, q = i; if (i < last_r) { int j = 2 * last_i - i; // (i + j) / 2 = last_i int slen = min(P[j], last_r - i); p-= slen; q+= slen; } while(p >= 0 && q < nlen && str[p] == str[q]) p--, q++; if (q > last_r) { last_r = q; last_i = i; } P[i] = q - i; if (P[i] > maxv) { maxv = P[i]; maxi = i; } } return s.substr((maxi + 1 - P[maxi]) / 2, P[maxi] - 1); } };
Manacher算法实现,不能懈怠
第二轮:
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
以前做得真是没什么印象了,因为题目中规定了不超过1000数量不大,先写个简单的:
// 13:37 class Solution { public: string longestPalindrome(string s) { int n = s.size(); if (n <= 1) { return s; } const char* str = s.c_str(); int maxlen = 1; int ts = 0, te = 0; int ms = 0, me = 0; for (int i=0; i<n; i++) { int tlen = countPal(str, i, n, ts, te); if (tlen > maxlen) { maxlen = tlen; ms = ts; me = te; } } return s.substr(ms, me-ms+1); } int countPal(const char* str, int mid, int n, int& s, int& e) { if (mid < 0 || mid >= n) return 0; int maxlen = 1; int l = mid - 1; int r = mid + 1; s = l; e = r; while (l >= 0 && r < n && str[l] == str[r]) { if (r - l + 1 > maxlen) { maxlen = r-l+1; s = l; e = r; } l--, r++; } l = mid; r = mid + 1; while (l >= 0 && r < n && str[l] == str[r]) { if (r - l + 1 > maxlen) { maxlen = r - l + 1; s = l; e = r; } l--, r++; } return maxlen; } };
i为当前遍历到的字符,如果它在一个已知的回文串内(即last_r>i,last_r为已知的回文串中右端最靠右的索引+1),那么在这个回文串内存在一个和i关于该回文串中心last_i的一个对称位置j(设已经由先前步骤记录为last_i,它和last_r是同一个已知回文串的参数)。如果在j位置上存在一定长度的回文串,那么在i上也回同样的存在。但它们的长度很可能是不一样的,有下面几种情况
1. 如图中的情况A段回文串已经超出了以last_i为中心的回文范围,所以我们可以直接判断是回文的部分只有B段,剩下的部分还是需要一一比较。
2. 如果图中的A段完全在已知回文串内,则以i为中心的回文串至少和以j为中心的回文长度一致,外延部分需要逐一比较
int slen = min(P[j], last_r - i);
P为存储回文中心到回文外延的长度数组
改写一下代码:
class Solution { public: string longestPalindrome(string s) { int len = s.size(); string ms = "$"; for (int i=0; i<len; i++) { ms.push_back(s[i]); ms.push_back('$'); } int mlen = ms.size(); vector<int> dp(mlen, 1); int far = 0; int lcenter = 0; int maxlen = 0; int center = 0; for (int i=0; i<mlen; i++) { int p = i, q = i; if (i < far) { int mirror = 2 * lcenter - i; int step = min(far - i, dp[mirror]); p-=step; q+=step; } while (p >= 0 && q < mlen && ms[p] == ms[q]) { p--, q++; } if (q > far) { far = q; lcenter = i; } dp[i] = q - i; if (dp[i] > maxlen) { maxlen = dp[i]; center = i; } } int slen = (maxlen * 2 - 1) / 2; int start = (center - maxlen + 1) / 2; return s.substr(start, slen); } };