Manacher最长回文串匹配
复习又学习了两遍。
Manacher讲究以线性时间复杂度解决寻找字符串中的最长回文串。
1.将字符串预处理,统一了奇数偶数长度的字符串——在字符串中给字符添加分隔符。
这里是将s处理后得到S字符串。
void init(string s) { S[0] = '@'; int l = s.length(); for (int i = 1; i <= l * 2; i += 2) { S[i] = '#'; S[i + 1] = s[i / 2]; } S[l * 2 + 1] = '#'; }
2.一个数组p[i]表示以i位置为中心的回文串最长长度。
这个数组有一个性质,p[i]-1即表示了原串回文串的长度
证明如下:
首先在所有转换后的字符串S中,所有回文串长度都为奇数
也即,对于p[i]为中心的最长回文串,其长度就是p[i]*2-1
又因为分隔符的数量一定比原字符多1,也就是有p[i]个分隔符,剩下p[i]-1个字符是原字符串
所以该回文串在原字符串的长度就是p[i]-1
现在的任务就是一步一步将p[i]给从头处理到尾(从左到右)即可得到结果。
3.p[]数组的计算,需要变量【id表示当前已计算的最长回文串中心,mx表示当前已计算的最长回文串的最右端下标】
下面分两个部分,一个是在已计算区间找p,一个是未计算区间找p
(为什么这么说?不是都要计算的吗?答:利用对称性,当已得到的最长回文串的最右端mx大于当前遍历中心i,那么一定且肯定当前p[i]可以省略计算)
3.1已计算区间找p
也即mx>i,很简单,现在的p[i]是 已知回文串的一半 的 一个部分,那么直接去找 另一半 的 对应部分 的p即可,
也即p[i]=p[id-(i-id)]
需要注意的是:有可能 这个对称部分 不完全包括在 那一个已知的回文串中
也就是需要考虑极限对称长度mx-i即可
总结就是p[i]=min(p[id-(i-id)],mx-i)
3.2未计算区间找p
p[i]=1,然后直接也只能暴力匹配——【while(S[i-p[i]==S[i+p[i])++p[i]】
当更新到i+p[i]>mx时候要更新mx和id
如上循环结束匹配即Manacher
示范代码:
#include <bits/stdc++.h> using namespace std; #define N 202200 #define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); #define cn(s) cout << s << endl typedef long long ll; int p[N * 2]; string S; void init(string s) { S[0] = '@'; int l = s.length(); for (int i = 1; i <= l * 2; i += 2) { S[i] = '#'; S[i + 1] = s[i / 2]; } S[l * 2 + 1] = '#'; } void solve(string s) { init(s); int mx = 0, id = 0, l = s.length() * 2, ans = 0; for (int i = 0; i < l; ++i) { if (mx > i) p[i] = min(p[id - i + id], mx - i); else p[i] = 1; while (S[i - p[i]] == S[i + p[i]]) ++p[i]; if (p[i] + i > mx) { mx = p[i] + i; id = i; } ans = max(ans, p[i]); } cn(ans - 1); } int main() { IOS; string s; while (cin >> s) solve(s); return 0; }
C++,version:
class Solution { string S, ans; void Init(string s) { S = "~#"; for (auto i : s) S = S + i + '#'; } string manacher(string s, string fs) { int mx = 0, id = 0, l = s.length(), res = 0, start = 0; vector<int> p(l); for (int i = 1; i < l; ++i) { if (mx > i) p[i] = min(mx - i, p[id - (i - id)]); else p[i] = 1; while (s[i - p[i]] == s[i + p[i]]) ++p[i]; if (p[i] + i > mx) { mx = p[i] + i; id = i; } if (p[i] > res) { res = p[i]; // ans = s.substr(id - p[i] + 1, 2 * p[i] - 1); ans = fs.substr((id - p[i]) / 2, p[i] - 1); } } return ans; } public: string longestPalindrome(string s) { Init(s); return manacher(S, s); } };
学习博客:https://blog.csdn.net/dyx404514/article/details/42061017

浙公网安备 33010602011771号