情况分析: (1)当前点 i 不在回文右边界里:暴力扩充,无优化,直接扩 (2)当前点 i 在回文右边界里: L:左边界,R:右边界,C:中心点,i‘ :i 关于C的对称点 在回文半径数组中可以得到,i’ 的回文情况 (a ) i’ 的回文区域在L内部,则 i 的回文半径就是 i‘ 的回文半径 (b ) i’ 的回文区域有一部分已经在L外部,那么 i 的回文半径就是 i 到 R的部分 (c ) i‘ 的回文区域与L重合,i 的回文半径一定 >= i 到 R 的部分,需要对R 后的东西与R关于 i 的对称点 R’ 进行比较,判断回文区域
时间复杂度O(N),N为字符个数
代码实现
若使用情况分析的结果挨个判断实现代码太过繁琐
可以整合无需判断回文的部分,得到对应的回文半径后,跳过无需判断的部分后,剩余代码部分情况全部判断是否能扩张 (1)情况1,无需比较的部分就是自己回文半径从1开始 (2)情况2,a的情况是最小值,b与c都是基于回文右边界 - i,则比较preArr[ i‘ ] 与 R - i + 1的大小,取较小值就是不用判断的部分
publicstaticintmanacher(String str){if(str ==null|| str.length()==0){return0;}char[] chs =manacherString(str);//添加特殊字符int[] preArr =newint[chs.length];//回文半径数组int mid =-1;//回文中心intR=-1;//回文右边界int max =Integer.MIN_VALUE;//最大回文长度for(int i =0; i < chs.length; i++){//遍历字符数组//不用判断的区域//i <= R当前点i不在右边界,回文半径至少是 1//i在右边界的两种情况:i'的回文在 L内,或者L外i//通过对称点 i’ 或者 R - i中的最小值,就可判断时哪一种情况
preArr[i]=R> i ?Math.min(preArr[2* mid - i],R- i +1):1;while(i + preArr[i]< chs.length && i - preArr[i]>-1){//不超过左右字符数组的情况下//无论是哪一种情况都判断能否扩张,使得代码精简if(chs[i + preArr[i]]== chs[i - preArr[i]]){//满足扩展
preArr[i]++;}else{break;}}if(i + preArr[i]>R){//更新R,midR= i + preArr[i]-1;
mid = i;}
max =Math.max(max, preArr[i]);}//原字符串是扩充串回文半径 - 1return max -1;}publicstaticchar[]manacherString(String str){//添加特殊字符,使得回文字符的长度全部变成偶数char[] strArr = str.toCharArray();char[] chs =newchar[str.length()*2+1];for(int i =0, j =0; i < chs.length; i++){//偶数位置加入特殊字符
chs[i]=(i &1)==0?'#': strArr[j++];}return chs;}