时间复杂度:O(n)
空间复杂度:O(n)
public class longestPalindrome_5 {
public static void main(String[] args) {
String s = "babac";
System.out.println(new longestPalindrome_5().longestPalindrome(s));
}
/*
manachaer 算法
*/
public String longestPalindrome(String s){
char[] res = helper(s);
int[] PArr = new int[res.length];//回文半径数组(以当前数的位置为中心的回文数组的半径)
//R是当前最大回文半径的最右边界的右一个值(也就是最大回文数组的右边界向后移动一个位置,有效的回文半径区域是 R - 1)
//C是当前R最大的时候的圆心位置
int R = -1,C = -1;
int maxL = Integer.MIN_VALUE;
for(int i = 0;i != res.length;i++){
//当R < i时,当前字符的位置不在R内,继续往外扩散,加速的位置是自身,即是1
//当R > i时,当前字符的位置在R内,以C为对称点,找i的对称点i'
//1.i'的回文半径在R内或者在R内;那么i的回文半径就是i'位置的回文半径, PArr[i'];
//2.i'的回文半径和以C为对称点R的对称点R'重合,那么i的回文半径最低长度为R - i(该算法的加速的地方),需要在向R的后边继续扩散判断是否能成功
PArr[i] = R > i ?Math.min(PArr[2 * C - i],R - i):1;
while(i + PArr[i] < res.length && i - PArr[i] > -1 ){
if(res[i + PArr[i]] == res[i - PArr[i]]){//往外扩散判断,该分支其实是 当R < i 和 当R > i,且i'的回文半径与R'重合的情况执行的,
PArr[i]++;//扩成功当前字符的回文半径数组增加
}else{//R > i,i'的回文半径在R'之内和之外执行的,不用扩散,
break;
}
}
//每次判断当前最右的回文半径的右边界是否是最右的,不是就更新,同时也更新对称点的位置,R 和 C是一一对应的
if(R < i + PArr[i]){
R = i + PArr[i];
C = i;
}
//每次记录最大回文的最大长度
maxL = Math.max(maxL,PArr[i]);//max - 1 就是最长回文子串的长度
}
return maxL;
}
/*
处理字符串,添加特殊字符(字符可以是任意)
*/
public char[] helper(String s){
char[] str = s.toCharArray();
char[] res = new char[str.length * 2 + 1];
int index = 0;
for (int i = 0; i != res.length; i++) {
res[i] = (i & 1) == 0 ?'#':str[index++];
}
return res;
}
}