九度笔记之 1528:最长回文子串 用manacher算法
来源:互联网 发布:js怎么给隐藏域赋值 编辑:程序博客网 时间:2024/05/19 02:19
题目1528:最长回文子串
- 题目描述:
回文串就是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。
回文子串,顾名思义,即字符串中满足回文性质的子串。
给出一个只由小写英文字符a,b,c...x,y,z组成的字符串,请输出其中最长的回文子串的长度。
- 输入:
输入包含多个测试用例,每组测试用例输入一行由小写英文字符a,b,c...x,y,z组成的字符串,字符串的长度不大于200000。
- 输出:
对于每组测试用例,输出一个整数,表示该组测试用例的字符串中所包含的的最长回文子串的长度。
- 样例输入:
ababbbbbabba
- 样例输出:
344
算法分析
manacher 算法可以参考http://blog.csdn.net/ggggiqnypgjg/article/details/6645824
首先:大家都知道什么叫回文串吧,这个算法要解决的就是一个字符串中最长的回文子串有多长。这个算法可以在O(n)的时间复杂度内既线性时间复杂度的情况下,求出以每个字符为中心的最长回文有多长,
这个算法有一个很巧妙的地方,它把奇数的回文串和偶数的回文串统一起来考虑了。这一点一直是在做回文串问题中时比较烦的地方。这个算法还有一个很好的地方就是充分利用了字符匹配的特殊性,避免了大量不必要的重复匹配。
算法大致过程是这样。先在每两个相邻字符中间插入一个分隔符,当然这个分隔符要在原串中没有出现过。一般可以用‘#’分隔。这样就非常巧妙的将奇数长度回文串与偶数长度回文串统一起来考虑了(见下面的一个例子,回文串长度全为奇数了),然后用一个辅助数组P记录以每个字符为中心的最长回文串半径的信息。P[id]记录的是以字符str[id]为中心的最长回文串的半径,当以str[id]为第一个字符,这个最长回文串向右延伸了P[id]个字符。
原串: w aa bwsw f d
新串: # w# a # a # b# w # s # w # f # d #
辅助数组P: 1 2 1 2 3 2 1 2 1 2 1 4 1 2 1 2 1 2 1
这里有一个很好的性质,P[id]-1就是该回文子串在原串中的长度(包括‘#’)。
怎么在线性时间内求P[i]呢,我们还要用到一个辅助的mx, 表示i之前 回文串 所能影响到的最右边的位置,用id记录mx所属的回文串的id.
算法关键为
if(mx>i){ mLen[i] = max(mLen[2*id-i],mx-i+1); }
华丽的分割
————————————————————————————————————————————————
第一种情况 mx>i+p[i]
由于以id为中心的 回文字符串 左右两边是对称的,所以 以i为中心的回文字符串和以2*id-1(也即是 i以id为中心的对称点)的回文字符串是一样的。如下图:
第二种情况,mx<=i+p[i]
由p[id]和mx,我们仅能推断出p[i]至少为mx-i, mx后面的还没有比较,需要进一步比较确定。
求得p[i]后我们要记得更新一下mx,id.
另外一种逆向错位比较法参见:
1252:回文子串
源程序
//============================================================================// Name : judo1252Manacher.cpp// Author : wdy// Version :// Copyright : Your copyright notice// Description : Hello World in C++, Ansi-style//============================================================================ #include <iostream>#include <string>#include <vector>#include <cmath>using namespace std; void Manach(std::string &s){ std::vector<char> ns; ns.push_back('$'); ns.push_back('#'); int len = s.size(); for(int i = 0;i<len;i++){// become odd ns.push_back(s.at(i)); ns.push_back('#'); } len = ns.size(); int *mLen = new int[len]; //record max radius of sub string in the middle of id int mx = 0; int id = 0; int maxLen = 0; for(int i = 0;i<len;i++){ mLen[i] = 1; if(mx>i){ mLen[i] = max(mLen[2*id-i],mx-i+1); } while((i+mLen[i])<len && i-mLen[i]>0 && ns.at(i+mLen[i])==ns.at(i-mLen[i])) mLen[i]++; if(i + mLen[i]-1 >mx){ //update mx,id mx = i + mLen[i]-1 >mx; id = i; } if(mLen[i]>maxLen) //update maxLen maxLen = mLen[i]; } std::cout<<maxLen-1<<std::endl; } void judo(){ std::string s; while(std::cin>>s){ Manach(s); }} int main() { judo(); //cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!! return 0;} /************************************************************** Problem: 1252 User: KES Language: C++ Result: Accepted Time:0 ms Memory:1520 kb****************************************************************//************************************************************** Problem: 1528 User: KES Language: C++ Result: Accepted Time:150 ms Memory:7492 kb****************************************************************/
- 九度笔记之 1528:最长回文子串 用manacher算法
- 九度OJ 1528 最长回文子串 -- Manacher算法
- 最长回文子串 用manacher算法
- 寻找最长回文子串Manacher算法学习笔记
- 【字符串处理】最长回文子串笔记(Manacher算法)
- 求解最长回文子串 Manacher算法 之 POJ 3974
- 字符串之最长回文子串 manacher算法
- 求解最长回文子串 之Manacher算法
- Manacher算法求最长回文子串
- Manacher算法求最长回文子串
- 最长回文子串(Manacher算法)
- Manacher算法 最长回文子串
- 最长回文子串的manacher算法
- 最长回文子串,Manacher算法
- Poj3974 最长回文子串 Manacher算法
- 最长回文子串 manacher算法
- Manacher算法(最长子回文串)
- hihocoder1032(最长回文子串manacher算法)
- hdu 1664 Different Digits
- 关于在MFC中加载PNG图片
- hdu1086计算n条线段的交点个数
- CopyU!的内核引擎升级到1.2.288.104
- 小知识点集合
- 九度笔记之 1528:最长回文子串 用manacher算法
- Oracle 只读表空间 说明
- eclipse 阅读代码高效快捷键
- 银联+移动+三星PK微信、余额宝
- 在对xml进行操作完成之后一定要记得保存,否则等于没操作
- 沙盒解决方案与场解决方案之间的差异
- 黑马程序员--Java基础加强--10.【PropertyDescriptor操作JavaBean VS 反射操作Java类】【个人总结】
- 保护眼睛,设置Visual Studio(eclipse)文本编辑背景色为自然绿
- PAT_1052: Linked List Sorting