最长回文子串

来源:互联网 发布:济南行知小学学区划分 编辑:程序博客网 时间:2024/05/22 06:10

最高效的方法是Manacher算法,时间复杂度为O(N),在2N步内即可找到最长回文子串

Manacher算法的基本思想是用一个O(N)的数组P来存储每一个元素为中心时回文子串的长度

为了提高效率,还特别增加了两种措施:

1.对原字符串的首尾以及每个元素间都增加一个特殊字符(如#),使得新字符串的长度都变成奇数位

2.计算P[i]时会考虑到之前计算过的回文长度,设i之前最长回文子串位置为curcenter,则对应的回文子串长度为P[curcenter],右边界即为right=curcenter+P[curcenter]。根据i和right的关系,有三种情况:

(1) i>=right,说明当前元素i超出了curcenter的回文串范围,此时需要重新计算i的回文串长度,并把curcenter置为i

(2) i<right,且i相对于curcenter的对称点i'的子串长度为P[i'],i+P[i']也不超过right,说明i的子串仍然在right范围内,此时P[i]=P[i'],不需要计算

(3) i<right,但i+P[i']超过了right,说明i的子串超出了right范围,此时P[i]至少等于[i,right]区间的长度,right以外的回文串长度需要额外计算


代码:

#include <iostream>#include <string>using namespace std;int findMaxDasLen( const string& str , int& center , int& sublen ){//计算str的最长回文子串长度并返回int len = str.length();if( len <= 1 )return len;string newstr;for( string::const_iterator it=str.begin() ; it!=str.end() ; it++ ){//每个字符间加上#newstr += "#";newstr += (*it);}newstr += '#';int newLen = newstr.length();//加完#后的字符串长度int* P = new int[ newLen ];//用来存储以每个元素为中心的最长回文串长度P[0] = 1;//第一个字符是#,最大回文长度为1int curcenter = 0;//初始中心位置是0for( int pos=1 ; pos<newLen ; pos++ ){int right = curcenter + P[curcenter];//右边界坐标int lpos = 2*curcenter-pos;//左对称点坐标if( pos>=right )P[pos] = 1;//pos在右边界外,需要从头计算回文串长度else if( P[lpos] <= right-pos )P[pos] = P[lpos];//pos的回文串全在right以左elseP[pos] = right-pos;//pos的回文串部分在right以左while( pos+P[pos]<newLen && pos-P[pos]>=0 && newstr[pos+P[pos]]==newstr[pos-P[pos]] )P[pos]++;//检查pos为中心的回文串if( pos + P[pos] > right )curcenter = pos;//回文串超过右边界,更新中心位置}int maxpos=0;for( int i=1 ; i<newLen ; i++ ){if( P[i] > P[maxpos] )maxpos = i;}sublen = P[maxpos]-1;//原字符串中的最大回文串长度center = (maxpos)/2;//原字符串中的最大回文串中心坐标delete[] P;return sublen;}int main(){string str1 = "abaaba";string str2 = "aaaabaa";string str3 = "acacdas";int center=0;int sublen=0;cout << findMaxDasLen( str1 , center , sublen ) << endl;cout << str1.substr( center-(sublen)/2 , sublen ) << endl;cout << findMaxDasLen( str2 , center , sublen ) << endl;cout << str2.substr( center-(sublen)/2 , sublen ) << endl;cout << findMaxDasLen( str3 , center , sublen ) << endl;cout << str3.substr( center-(sublen)/2 , sublen ) << endl;system("pause");}

0 0
原创粉丝点击