问题:求一个字符串的最长回文子串。
解决方案:利用后缀数组,设这个字符串是S,S'是这个字符串的反转,设T=S+'$'+S',则所有的回文子串一定会出现在字符串T当中的其中两个后缀的前缀上,所以只要求T的lcp,利用lcp求后缀之间的相同前缀的最大长度。
代码参考:
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<algorithm> #include<vector> #include<cstring> #include<string> #include<cmath> using namespace std; const int INF = 0x3f3f3f3f; const int N_MAX = 100000 + 20; typedef long long ll; int n, k; int Rank[N_MAX * 2]; int tmp[N_MAX * 2]; int sa[N_MAX * 2]; int lcp[N_MAX * 2]; bool compare_sa(const int& i, const int& j) { if (Rank[i] != Rank[j])return Rank[i] < Rank[j]; else { int ri = i + k <= n ? Rank[i + k] : -1; int rj = j + k <= n ? Rank[j + k] : -1; return ri < rj; } } void construct_sa(const string& S, int *sa) { n = S.size(); for (int i = 0; i <= n; i++) { sa[i] = i; Rank[i] = i < n ? S[i] : -1; } for (k = 1; k <= n; k *= 2) { sort(sa, sa + n + 1, compare_sa); tmp[sa[0]] = 0; for (int i = 1; i <= n; i++) { tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0); } for (int i = 0; i <= n; i++) { Rank[i] = tmp[i]; } } } void construct_lcp(const string& S, int *sa, int *lcp) { memset(lcp, 0, sizeof(lcp)); int n = S.length(); for (int i = 0; i <= n; i++)Rank[sa[i]] = i; int h = 0; lcp[0] = 0; for (int i = 0; i < n; i++) { int j = sa[Rank[i] - 1]; if (h > 0)h--; for (; j + h < n&&i + h < n; h++) { if (S[j + h] != S[i + h])break; } lcp[Rank[i] - 1] = h; } } int min_lcp[N_MAX * 2]; void rmq_init(int k, int l, int r) {//节点k的区间[l,r) if (r <= l)return; if (r - l == 1) { min_lcp[k] = lcp[l]; } else { int chl =2*k + 1, chr = 2*k + 2; int mid = (l + r) >> 1; rmq_init(chl, l, mid); rmq_init(chr, mid, r); min_lcp[k] = min(min_lcp[chl], min_lcp[chr]); } } int query_rmq(int a, int b, int k, int l, int r) { if (b <= l || a >= r) { return INF; } else if (a <= l&&b >= r) { return min_lcp[k]; } else { int mid = (l + r) >> 1; int min_L = query_rmq(a, b,2*k + 1, l, mid); int min_R = query_rmq(a, b, 2*k + 2, mid, r); return min(min_L, min_R); } } string s; int main() { while (cin >> s) { int N = s.size(); string T = s; reverse(T.begin(), T.end()); s += '$' + T; n = s.size(); construct_sa(s, sa); construct_lcp(s, sa, lcp); for (int i = 0; i <= s.size(); i++)Rank[sa[i]] = i; rmq_init(0,0,s.size()+1); int ans = 0; for (int i = 0; i < N; i++) { int j = 2 * N - i; int l = query_rmq(min(Rank[i], Rank[j]), max(Rank[i], Rank[j]), 0, 0, s.size()+1); cout <<"l:"<< l << endl; ans = max(ans,2*l-1); } for (int i = 1; i < N;i++) { int j = 2 * N - i + 1; int l = query_rmq(min(Rank[i], Rank[j]), max(Rank[i], Rank[j]), 0, 0, s.size()+1); cout << "l:" << l << endl; ans = max(ans, 2 * l); } printf("%d ",ans); } return 0; } //mississippi