Manacher算法
Manacher算法
什么是Manacher算法:
Manacher算法是一种用于寻找最长回文子串的算法,时间复杂度为O(n),其中n是字符串的长度。该算法是由Gusella和Shannon于1980年提出的,它利用了回文串的特殊性质,以实现高效的查找。
算法步骤如下:
1. 初始化一个数组p,p[i]表示以字符i为中心的最长回文子串的半径长度(即回文串的长度除以2)。
2.初始化一个变量max_len,用于记录已经找到的最长回文子串的长度,初始值为0。
3. 从左到右遍历字符串,对于每个字符i,进行以下操作:
a. 如果i的左侧和右侧都有回文子串,则更新max_len为左侧回文子串长度和右侧回文子串长度的较大值,并更新p[i]为max_len的一半。
b. 如果i的左侧没有回文子串,则将p[i]设为0。
c. 如果i的右侧没有回文子串,则将p[i]设为max_len的一半。
4. 在遍历过程中不断更新max_len和p数组,最终得到的max_len即为最长回文子串的长度。
通过遍历p数组,可以得到最长回文子串的中心字符和长度。
Manacher算法的关键在于如何利用已经找到的回文子串信息来快速判断新的字符是否能够扩展已有的回文子串。通过维护p数组,可以在O(1)的时间内得到新字符能够扩展的最长回文子串长度,从而实现高效的查找。
该算法的实现比较简单,时间复杂度较低,因此在处理长回文子串的问题时具有很好的应用价值。
代码演示
/**
* 最长回文串的长度处理
* @param s
* @return
*/
public static int manacher(String s) {
if (s == null || s.length() == 0){
return 0;
}
// abc -> #a#b#c#
char[] chars = manacherString(s);
//回文半径数组
int[] pArr = new int[chars.length];
//回文最右边界
int R = -1;
//回文中心
int C = -1;
//保存最大值
int max = Integer.MIN_VALUE;
for (int i = 0; i < chars.length;i++){
//i 在R 的半径内。
pArr[i] = R > i ? Math.min(pArr[2 * C - i],R - i) : 1;
while (i + pArr[i] < chars.length && i - pArr[i] > -1){
if (chars[i + pArr[i]] == chars[i - pArr[i]]){
pArr[i]++;
}else {
break;
}
}
if (i + pArr[i] < chars.length){
R = i + pArr[i];
C = i;
}
max = Math.max(max,pArr[i]);
}
return max - 1;
}
/**
* 处理字符串 abc -> #a#b#c#
* @param str
* @return
*/
public static char[] manacherString(String str){
char[] chars = str.toCharArray();
char[] ans = new char[chars.length * 2 + 1];
int index = 0;
for (int i = 0 ; i < ans.length;i++){
ans[i] = (i & 1) == 0 ? '#' : chars[index++];
}
return ans;
}