回文串算法Manacher
2017-12-26 20:31
99 查看
回文串算法Manacher
首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。 为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊字符,这样就不用特殊处理越界问题,比如$#a#b#a#。下面以字符串12212321为例,经过上一步,变成了 S[] = “$#1#2#2#1#2#3#2#1#”;
然后用一个数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i]),比如S和P的对应关系:
S # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 #
P 1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1
(p.s. 可以看出,P[i]-1正好是原字符串中回文串的总长度)
下面计算P[i],该算法增加两个辅助变量id和mx,其中id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界。
这个算法的关键点就在这里了:
Mp[i] = mx > i ? min(Mp[2*id-i],mx-i):1;
其实就是对称点和边界的问题。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1000010; char Ma[maxn*2]; int Mp[maxn*2]; char s[maxn]; void Manacher(char s[],int len) { int l = 0; Ma[l++] = '$'; Ma[l++] = '#'; for(int i = 0;i < len; i++) { Ma[l++] = s[i]; Ma[l++] = '#'; } Ma[l] = 0; int mx = 0,id = 0; for(int i = 0;i < l; i++) { Mp[i] = mx > i ? min(Mp[2*id-i],mx-i):1; while(Ma[i+Mp[i]] == Ma[i-Mp[i]]) Mp[i]++; if(i + Mp[i] > mx) { mx = i + Mp[i]; id = i; } } } int main() { freopen("in.txt","r",stdin); int ncase = 1; while(scanf("%s",s) == 1) { if(strcmp(s,"END") == 0) break; int len = strlen(s); Manacher(s,len); int ans = 0; for(int i = 0;i < 2*len+2; i++) ans = max(ans,Mp[i]-1); printf("Case %d: %d\n",ncase++,ans); } return 0; }
相关文章推荐
- 算法学习--字符串--最长回文子串
- UVA 12378 Ball Blasting Game
- Manacher算法
- 647 Palindromic Substrings
- O(N)最长回文子串算法——Manacher算法
- 最长回文子串
- 2016-8-6夏令营总结(kmp,回文串,扩展kmp)
- manacher算法
- 【HDU3294,URAL1294】manacher算法
- HDOJ-3068 最长回文 (manacher求最长回文串)
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher算法
- man拉車
- Manacher——最大回文子串的线性算法
- HDU 3608 最长回文 manacher算法
- <学习笔记>manacher算法
- E - 最长双回文串 HYSBZ - 2565
- Manacher最长回文子串(模板)
- HDU3068 最长回文(manacher)
- HDU3294 Girls' research(Manacher算法)