复杂算法介绍[4]-Manacher算法实现
直接上代码:
public class Manacher {
/**
* 字符串的最长回文子串
*
* 回文串就是字符串关于中间镜面对称
*
* 假设字符串是
* fabccba
*
* 最长回文串就是abccba
*
*
*
*/
/**
*
* 暴力解
*
* 找到以每个字符为中间的最长回文串是多长
*
* fabccba
*
* 依次找以f为中心,a为中心,但是需要分奇数偶数,可以补长一倍长度字符串变成
*
* fabccba===>#f#a#b#c#c#b#a#,就不需要区分奇数偶数了,#位置的就是当最长回文是偶数时的中间位置
*
* 最后回文长度就是求出的长度/2
*
*
*
*/
/**
* 解法2,也需要补长度
*
* fabccba===>#f#a#b#c#c#b#a#
*
* 见manacher算法相关文档
*
*
*
*/
public static int manacher(String s){
if(s == null || s.length()==0){
return 0;
}
char[] str = manacherString(s);
int[] pAry = new int[str.length];
int C =-1;
int R =-1; //R是第一个不匹配的位置
int max = Integer.MIN_VALUE;
for (int i = 0; i < str.length; i++) {
pAry[i] = i<R? Math.min(pAry[2*C-i],R-i):1; //当i>=R,标识已经到R外部,要使用暴力扩展,但是自己肯定恨自己是回文,所以初始值是1
while(i+pAry[i]<str.length && i-pAry[i]>-1){
if(str[i+pAry[i]] == str[i-pAry[i]]){ //如果i<R,则这个判断会不成立,循环直接退出
pAry[i]++;
}else{
break;
}
}
//更新右边界
if(i+pAry[i]>R){
R = i + pAry[i];
C = i;
}
max = Math.max(max,pAry[i]);
}
return max -1;
}
public static char[] manacherString(String s){
char[] charArr = s.toCharArray();
char[] res = new char[2*charArr.length+1];
int index = 0;
for (int i = 0; i != res.length; i++) {
res[i] = (i&1) ==0 ?'#':charArr[index++];
}
return res;
}
public static void main(String[] args) {
String s = "fabccba";
System.out.println(manacher(s));
}