一种快速求解最长回文字符串长度的算法
来源:互联网 发布:马甲网络 编辑:程序博客网 时间:2024/04/30 00:11
最近在做OJ时遇到一个题——求解一个字符串最长回文子串的长度,题目如下:
- 样例输入
3abababaaaaabaaacacdas
- 样例输出
753
描述
小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。
这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?”
小Ho奇怪的问道:“什么叫做最长回文子串呢?”
小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~”
小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢?
小Hi笑着说道:“这个很容易啦,你只需要写一个程序,先从标准输入读取一个整数N(N<=30),代表我给你的字符串的个数,然后接下来的就是我要给你的那N个字符串(字符串长度<=10^6)啦。而你要告诉我你的答案的话,只要将你计算出的最长回文子串的长度按照我给你的顺序依次输出到标准输出就可以了!你看这就是一个例子。”
首先是分析自己算法浪费时间的地方:一是要分奇数和偶数两种情况考虑,二是没有利用前面查找工作得到的结果。而这两点正是Manacher算法的优越之处,下面开始分析:
首先是如何利用前面的查找结果的,Manacher算法实际上是利用了回文字符串的一个特性——对称性。
例如一个字符串:abababa 最长回文子串就是本身abababa,中心字符为第四个字符b,而实际上我们可以发现在考察以第六个字符b为中心字符的回文字符子串的时候,是与考察以第二个字符b为中心字符的回文字符子串的情况相同的,所以是可以不必重复算的,这种算法本质上是一种动态规划思想,当然这么做有个问题就是作为参照的中心字符(上文的第四个字符b)的回文子串范围没有这么大的时候,结果就错误了。
例如一个字符串:aabaabaabac 在考虑以第九个字符b为中心字符的回文字符子串的时候就不能和以与它对称的第三个字符为中心字符的回文子串最大长度相等,而是在回文子串最右范围内的部分。因此我们需要做的工作就是不断求取目前最右回文子串的右范围坐标maxid以及中心字符坐标id,而以当前坐标i为中心字符的最长回文子串的长度就是min(p[2*id-i],maxid-i)。我们在这里用一个整数组p存储。
这个方法还有一个问题就是必须回文字符串长度要是奇数才行,这个问题我上面也说过,而Manacher算法用一个很巧妙的方法解决了这个问题,就是将所有的字符串无论奇偶全部变为奇数个——在一个字符串开头结尾以及任意两个字符之间插入一个无用字符'#',
例如字符串"abab"——>"#a#b#a#b#",这样无论子串个数是奇是偶,就都变成了奇数个,问题也就解决了。
最后附上我的代码仅供参考:
#include<stdio.h>#include<string.h>#include<iostream>using namespace std;#define LENGTH 10000000 //数组大小char str[LENGTH],newstr[2*LENGTH];int p[2*LENGTH];int min(int a,int b){return a<b?a:b;}void Change(char* str,char* newstr,int len) //转换字符串函数{int i;newstr[0]='#';for (i=0;i<len;i++){newstr[2*i+1]=str[i];newstr[2*i+2]='#';}newstr[2*i+1]='\0';}void Manacher(char* newstr,int len){int id,ans=1,maxid=0; //ans记录当前最大长度值for (int i=0;i<len;i++){if (maxid>i){p[i]=min(p[2*id-i],maxid-i);}else{p[i]=1;}while ((newstr[i+p[i]]==newstr[i-p[i]])&&(i-p[i])>=0&&(i+p[i])<len) p[i]++; if (p[i]+i>maxid){ maxid=p[i]+i; id=i; } if (ans<p[i]) ans=p[i];}cout<<ans-1<<endl;}int main(){int n,i,l;cin>>n;while(n-->0){cin>>str;l=strlen(str);Change(str,newstr,l);Manacher(newstr,l*2+1);}return 0;}
- 一种快速求解最长回文字符串长度的算法
- 字符串的最长回文长度
- 求解最长回文子串的长度
- 求解最长回文字符串
- 字符串中最长的回文字符串长度
- 求解最长回文字符串的方法
- pat 中求解最长回文串的长度
- 算法3—找出字符串中对称的子字符串的最大长度(最长回文)
- 求解最大回文字符串长度 — 三种算法
- 对于一个字符串,请设计一个高效算法,计算其中最长回文子串的长度。
- 字符串中对称字符串的最大长度(最长回文)
- 字符串最长回文算法
- Manacher's Algorithm 求解字符串的最长回文串
- POJ3974 求字符串的最长回文子串的长度
- 一个字符串的最长回文子串的长度
- 求字符串中的最长回文子串的长度
- JAVA:返回字符串中最长回文子串的长度
- 输出任意字符串中最长的回文长度
- Sql2008 r2 使用ftp 发布和订阅方式同步数据
- jsp最终输出html时,如何去除大量空行
- i.MX6qSabreLite内核源码阅读笔记-----board-mx6q_sabrelite.c 分析----2
- CKEditor+SWFUpload实现功能较为强大的编辑器(一)---CKEditor配置
- EEPlat PaaS平台的UI模型
- 一种快速求解最长回文字符串长度的算法
- android实现session保持【以及web登陆保持】
- C++之国际化(3) --- facet
- margin和padding的区别
- c#静态方法和非静态方法区别
- 一起来当网管(一)——Windows Server上的DHCP配置
- Codeforces Round #254 (Div. 2)444A - DZY Loves Physics (枚举权值求最大)
- linux内核栈与用户栈
- 倚昌教学一体机给用户最强的体验