Manacher算法是用来查找字符串中的最长回文子串的线性算法,时间复杂度为O(n)
假设字符串为cbcbcbde
解析:
- 预处理在相邻字符间加上特殊字符#,将字符串长度奇数化。很好的解决了cbbc偶数回文的匹配问题。
- LCR,L表示当前已匹配回文中右边界值最大的回文子串的左边界值(未使用),C表示当前已匹配回文中右边界值最大的回文子串的中心值(使用),R表示当前已匹配回文中右边界值最大的回文子串的右边界值(使用)。因为我们是从左向右循环,所以需要使用到的是右边界值,LCR代表的就是一个已匹配的回文串的位置信息,那么在一个回文字符串中有一个很容易发现的事,在未超出边界线时,若对于中心点C两边的字符求回文串,求出来的回文串是相同的。
以下是js的manacher代码,只是求除了预处理后的各个位置的回文半径。
function manacher(str){//str = cbcbcbde
let Res = [],
R = 0,// R表示当前边界值最大的回文子串的边界值
C = 0,// 中心i
i,
newStr = '#',
len = str.length;
// 将字符串转化为奇数长度获取到新的字符串
for(i = 0; i < len ; i++){ //处理成#c#b#C#b...
newStr += str[i]+'#';
}
let newLen = newStr.length;
for(i = 0; i < newLen ; i++){//Res数组清零
Res[i] = 0;
}
for (i = 0;i < newLen; i++) {//循环
Res[i] = R > i ? Math.min(Res[2*C-i], R-i) : 1;//如果R大于i则获取对称位i和R-i对比的最小值
while ((newStr[i + Res[i]] === newStr[i - Res[i]]) && newStr[i + Res[i]]){//超出R的话继续匹配回文
Res[i]++;
}
if (i + Res[i] > R) {// 更新边界最大的回文子串的中心位置以及边界值
C = i;
R = C + Res[i];
}
}
return Res;
}