package manacher;
/*
* manacher的核心是回文半径数组,回文字符串的顺序逆序是一样的,字符是对称的,确定好的会问半径长度就可以帮助用来判断后面的i位置的回文半径,
* 首先是对字符串重新构造加上一个新字符,这个字符没有限制
* 使用字符填充后的数组构造出一个存储每个字符回文半径的数组
*构造会问半径数组rl时要注意愤青四种情况,以及每种情况的处理方式
*
*
* */
public class manacher {
public static char[] geneManaArr(String s){
char[] sb = s.toCharArray();
char[] str=new char[sb.length*2+1];
int index=0;
for(int i=0;i<str.length;i++){
// if((i&1)==0){
// str[i]='#';
// }else{
// str[i]=sb[index++];
// }
str[i]=((i&1)==0)?'#':sb[index++];
}
return str;
}
public static int[] manach(String string){
char[] geeArr = geneManaArr(string);
int c=-1;//最新的中心位置
int r=-1;//当前最新扩充的右边界,c r每次扩充玩结束更新
int[] rl=new int[geeArr.length];
for(int i=0;i<geeArr.length;i++){
//在i<R给当前位置的字符一个至少不用判断的回文串长度,i>=R赋值为1并自己扩张
//Math.min(r-i,rl[2*c-i]就是三种情况,i'的半径在L-R内部(r-i),外部以及压线L时(rl[2*c-i])对应的回文半径。区别在于压线时要进行进一步扩张判断。
//抓住回文串对称位置想等这一点,根据对称的i’半径,判断i的回文半径
rl[i]= i<r?Math.min(r-i,rl[2*c-i]):1;
//扩张策略在i>R以及压线时进一步判断,对每一个结果都进行扩充处理,对于i‘的半径在R内部以及外部这种确定的情况一次循环直接退出,其他两种扩充,不需要if语句
while((i-rl[i])>-1&&(i+rl[i])<rl.length){
if(geeArr[i-rl[i]]==geeArr[i+geeArr[i]]){
rl[i]++;
}else{
break;
}
}
if(i+rl[i]>r){
r=i+rl[i];
c=i;
}
}
return rl;
}
}
11-08
1363
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
08-29
7153
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)