为解决奇偶数回文,在字符串间添加任意辅助字符
abc->#a#b#c#
维护r和c,pArr[] r为回文最右边界,c是当前r的回文中心点,pArr[i]是i为中心时的回文半径
1)i不在r边界内,i>r
以i为中心点暴力扩,若扩后边界大于r,更新r,c
2)i在r边界内,存在L i' c i R 。LR,ii'关于c对称
再根据i'的回文状况划分
1)i‘回文在LR之间 i与i’的回文情况一致(对称)
2)i‘回文在LR之外 i的回文半径是i到R。LR之外必不相等。
3)i’回文正好压线LR i的回文半径至少是i到R,需要在该半径基础上继续扩。
共4情况,只有1,4会使得R变化
public static int maxLcp(String s){
if(s==null||s.length()==0){
return 0;
}
char[]str=manacherString(s);//abc->#a#b#c#
int[]pArr=new int[str.length];//回文半径数组
int C=-1;//回文中心
int R=-1;//回文右边界再右一个位置,R-1是有效区域,用于优化
int max=Integer.MIN_VALUE;
for(int i=0;i!=str.length;i++){
//不用验的区域
//R>i i在边界内or上,2*C-i是i‘的位置,R-i是i到右边界的位置
//i在R外时,该字符本身不用验,为1
pArr[i]=R>i? Math.min(pArr[2*C-i],R-i):1;
//上一步统一把不用验证的区域跳过,while中统一扩,
// 其中不需要扩的扩一步就会break,为了代码简洁
while(i+pArr[i]<str.length&&i-pArr[i]>-1){
if(str[i+pArr[i]]==str[i-pArr[i]]){
pArr[i]++;
}else{
break;
}
}
if(i+pArr[i]>R){
R=i+pArr[i];
C=i;
}
max=Math.max(max,pArr[i]);
}
//原串回文最大长度与回文半径存在以下关系
return max-1;
}
重点理解pArr[]的计算过程,Manacher算法的关键。