manacher算法总结与模版
manacher:可以解决最长回文问题。
算法:1.首先,将字符串的每个字符左右加入#,并在s0位置加入*(如果字符串中本身含有这些,则换成未出现过的字符),此时字符串的长度为len+len+3,即加入了len+1个#和一个*; (比如:aba变成 *#a#b#a#)
2.得到一个p数组,该数组是基于新字符串进行的。
得到p数组 :①从1~2*len遍历字符串,即从第一个#到最后一个字符(或者说*和最后一个#不用),即要得到p[1]~p[2*len];
②遍历的过程中,定义了两个新变量,id和mx,id标记的是,某个字符的位置;mx标记的是,能够匹配到了的最远的位置,而开始匹配的点为 id.换句话说:当处于id这个位置匹配回文的时候,mx到达了当前最远的位置,详细作用见代码。
③p数组的含义:达到某一个字符的时候,我们肯定要知道该字符能够与周围构成多长的回文,比如 s#b#a#b#t,中间哪个a,能够与#b#构成回 文,所以a这个位置的p值就为4,也就是说,p值代表的就是i这个位置的字符能够给出多长的回文串。
④匹配方法:我们可以看出,任何一个字符的p都至少为1(自己跟自己回文),那么我们只要当s[--i]==s[++j]的时候,让p++就可以了,知道两者不想等。但是,这样时间复杂度就高了很多,所以,我们要利用前面求的的p数组来减少不必要的匹配。
⑤减少匹配次数:利用mx和id以及对称性,具体看代码。
代码如下:
1 void manacher() //manacher 函数 2 { 3 int len=strlen(s); 4 for(int i=len;i>=0;--i) //将s扩大,中间加#,开头加* 5 { 6 s[i+i+2]=s[i]; 7 s[i+i+1]='#'; 8 } 9 s[0]='*'; 10 int id,mx=0; //mx代表以id为中心时,到达最远的位置 11 for(int i=1;i<len+len+1;++i) 12 { 13 if(mx>i) p[i]=min(p[2*id-i],mx-i); //如果到达最远位置大于当前匹配的地方,则p[i]取min(id的对称点的p,到达最远距离-i) 14 else p[i]=1; //如果i在mx右方,则p[i]=-1; 15 while(s[i-p[i]] == s[i+p[i]])++p[i]; //判断i回文长度 16 if(i+p[i]>mx) //看是否要更新最远距离,如果要,将此点作为中心。 17 { 18 id=i; 19 mx=p[i]+i; 20 } 21 } 22 }
浙公网安备 33010602011771号