manacher算法_求最长回文子串长度
很好的总结,转自:
http://blog.csdn.net/dyx404514/article/details/42061017
总结为:两大情况,三小情况。
两大情况:I. i <= p
1.要处理的位置i及i为中心的回文半径Len[i] < p-i已经完全包含在某个回文中了,这种情况不用计算,len[i] = len[j]。
2.要处理的位置i在某个回文中,但是以i为中心的回文半径len[i] >= p-i,需要往后匹配,重新更新p,及对应的po和Len[i];
II. i > p
要计算的位置已经超出某个回文了,之前的回文已经没用,要重新计算新的位置了。只能挨个匹配了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // manacher.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <iostream> 6 #include <string> 7 #include <vector> 8 #include <iterator> 9 using namespace std; 10 11 string ManaStr(string &orgStr,int length) 12 {//构造“马拉车”串 13 if(length == 0) 14 return NULL; 15 16 string manacherString(2*length+1,'#'); 17 for(int i = 0;i < length;i++) 18 manacherString[2*i+1] = orgStr[i]; 19 20 cout<<manacherString<<endl; 21 return manacherString; 22 } 23 24 int manacher(string &manStr,int manacherLen) 25 {//“马拉车”计算过程,主要是每个位置对应的回文半径数组的生成,pArr[i] 26 if(manacherLen == 0) 27 return 0; 28 29 int Len[25];//回文半径数组 30 for(int i = 0; i <25;i++) 31 Len[i] = 0; 32 for(int i = 0; i <25;i++) 33 cout<<Len[i]; 34 int po = 0;//某个回文中心 35 int mostRight = -1;//某个回文串最右的位置,并不包含这个位置 36 int result = 0; 37 38 //for(int i = 0;i != manacherLen;i++) 39 for(int i = 0;i != 25;i++) 40 { 41 Len[i] = mostRight > i ? min(mostRight-i,Len[2*po-i]):1; 42 /* 43 当前位置i包含在某个回文串中,那么Len[i]的值就是i到mostRight或者 44 关于po对称的j位置的Len值(j = 2*po-i) 45 */ 46 while(i+Len[i] < manacherLen && i-Len[i] >=0) 47 { 48 if(manStr[i - Len[i]] == manStr[i + Len[i]]) 49 Len[i]++;//检查是否可扩 50 else 51 break; 52 } 53 if(i+Len[i] > mostRight) 54 {//扩到mostRight之外了,旧的回文串就不起作用了,更新成新的回文串 55 //mostRight = Len[i] + 1;!!!!!!艹!!!会死人啊 56 mostRight = Len[i] + i; 57 po = i; 58 } 59 result = max(result,Len[i]); 60 } 61 return result - 1; 62 } 63 64 int _tmain(int argc, _TCHAR* argv[]) 65 { 66 string originalString = "abc1234321ab";//结果应该为7 67 int originalLen = originalString.length(); 68 //int originalLen = 12; 69 cout<<originalString<<endl; 70 string manacherString = ManaStr(originalString,originalLen); 71 int manStrLen = 2*originalLen + 1; 72 cout<<"原串中包含的最长回文长度为:"<<manacher(manacherString,manStrLen)<<endl; 73 system("pause"); 74 return 0; 75 }
一个变形题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // manacher_.cpp : 定义控制台应用程序的入口点。 2 //题目:给定一个串,求 在串的后边添加最小字符使得整体都是回文 3 //解法:利用manacher算法,当mostRight == length的时候停止,并记录下Len[i] 4 // 找到包含最后一个字符的回文串,之前的逆序就是要求的结果 5 //例子:abcd123321,在后边加dcba就是回文,返回dcba。 6 7 8 9 #include "stdafx.h" 10 #include <iostream> 11 #include <string> 12 using namespace std; 13 14 string manStr(string &orgStr,int orgLen) 15 { 16 if(orgLen == 0) 17 return NULL; 18 19 string manaString(2*orgLen+1,'#'); 20 //string的一种构造方法string(num,ele) 21 for(int i = 0; i < orgLen; i++) 22 manaString[2*i+1] = orgStr[i]; 23 24 cout<<manaString<<endl; 25 return manaString; 26 } 27 28 void manacherCore(string& mancherStr,int manaLen) 29 { 30 if(manaLen == 0) 31 return; 32 33 int mostEnd = 0; 34 int mostRight = -1; 35 int po = 0; 36 int Len[21]; 37 for(int i = 0; i< 21; i++) 38 Len[i] = 0;//初始化Len 39 40 for(int i = 0;i != manaLen; i++) 41 { 42 Len[i] = mostRight > i? min(mostRight - i,Len[2*po-i]):1; 43 //while(i+Len[i] < manaLen && i- manaLen > -1)麻痹又写错 44 while(i+Len[i] < manaLen && i- Len[i] > -1) 45 { 46 if(mancherStr[i + Len[i]] == mancherStr[i - Len[i]]) 47 Len[i]++; 48 else 49 break; 50 } 51 if(i + Len[i] > mostRight) 52 { 53 mostRight =i + Len[i]; 54 po = i; 55 } 56 if(mostRight == manaLen) 57 { 58 mostEnd = Len[i]; 59 break; 60 } 61 } 62 //string result(10-(mostEnd-1),'0');//保存结果的string 63 string result(10-mostEnd+1,'0');//这里应该是原串长度10 64 int resLen = result.length(); 65 66 for (int i = 0; i < resLen; i++) 67 result[resLen-i-1] = mancherStr[2*i+1]; 68 cout<<result<<endl; 69 70 } 71 72 int _tmain(int argc, _TCHAR* argv[]) 73 { 74 string orginalStr = "abcd123321"; 75 cout<<orginalStr<<endl; 76 int orgLen = orginalStr.length(); 77 string mancherStr = manStr(orginalStr,orgLen); 78 int manaLen = mancherStr.length(); 79 manacherCore(mancherStr,manaLen); 80 system("pause"); 81 return 0; 82 }