截止到目前我已经写了 500多道算法题,其中部分已经整理成了pdf文档,目前总共有1000多页(并且还会不断的增加),大家可以免费下载 下载链接:https://pan.baidu.com/s/1hjwK0ZeRxYGB8lIkbKuQgQ 提取码:6666
 之前在讲《517,最长回文子串的3种解决方式》的时候,在最后提到过Manacher算法,但是没有写,这里单独拿出来写。   我们来看个例子,比如字符串"babad"在添加特殊字符之后每个字符的回文半径
 

    如果还看不明白,我们来随便找个字符串 “babcbabcbac” 画个图来看下 
 代码如下,分三种情况判断
for (int i = 0; i < length; i++) {
if (i < maxRight) {
if (p[2 * maxCenter - i] < maxRight - i) {
p[i] = p[2 * maxCenter - i];
} else {
p[i] = maxRight - i;
while (i - p[i] >= 0 && i + p[i] < length && res[i - p[i]] == res[i + p[i]])
p[i]++;
}
} else {
p[i] = 1;
while (i - p[i] >= 0 && i + p[i] < length && res[i - p[i]] == res[i + p[i]])
p[i]++;
}
}
在来看下最终代码
public String longestPalindrome(String s) {
int charLen = s.length();
int length = charLen * 2 + 1;
char[] chars = s.toCharArray();
char[] res = new char[length];
int index = 0;
for (int i = 0; i < res.length; i++) {
res[i] = (i % 2) == 0 ? '#' : chars[index++];
}
int[] p = new int[length];
int maxRight = 0, maxCenter = 0, resCenter = 0, resLen = 0;
for (int i = 0; i < length; i++) {
if (i < maxRight) {
if (p[2 * maxCenter - i] < maxRight - i) {
p[i] = p[2 * maxCenter - i];
} else {
p[i] = maxRight - i;
while (i - p[i] >= 0 && i + p[i] < length && res[i - p[i]] == res[i + p[i]])
p[i]++;
}
} else {
p[i] = 1;
while (i - p[i] >= 0 && i + p[i] < length && res[i - p[i]] == res[i + p[i]])
p[i]++;
}
if (i + p[i] > maxRight) {
maxRight = i + p[i];
maxCenter = i;
}
if (p[i] > resLen) {
resLen = p[i];
resCenter = i;
}
}
resLen = resLen - 1;
int start = (resCenter - resLen) >> 1;
return s.substring(start, start + resLen);
}
上面都通过画图分析很好理解,可能稍微有点不好理解的是后面3行代码,resLen就是最大回文半径,resCenter就是最大回文子串(添加特殊字符之后的)中间的那个字符。我们可以根据下面这个图可以看到,原字符串中回文串的长度就是添加特殊字符之后的回文半径-1。
 上面是分为3种情况来判断的,实际上我们还可以把上面3种情况合并
p[i] = maxRight > i ? Math.min(maxRight - i, p[2 * maxCenter - i]) : 1;
while (i - p[i] >= 0 && i + p[i] < length && res[i - p[i]] == res[i + p[i]])
p[i]++;
我们来看下合并后的最终代码
public String longestPalindrome(String s) {
int charLen = s.length();
int length = charLen * 2 + 1;
char[] chars = s.toCharArray();
char[] res = new char[length];
int index = 0;
for (int i = 0; i < res.length; i++) {
res[i] = (i % 2) == 0 ? '#' : chars[index++];
}
int[] p = new int[length];
int maxRight = 0, maxCenter = 0, resCenter = 0, resLen = 0;
for (int i = 0; i < length; i++) {
p[i] = maxRight > i ? Math.min(maxRight - i, p[2 * maxCenter - i]) : 1;
while (i - p[i] >= 0 && i + p[i] < length && res[i - p[i]] == res[i + p[i]])
p[i]++;
if (i + p[i] > maxRight) {
maxRight = i + p[i];
maxCenter = i;
}
if (p[i] > resLen) {
resLen = p[i];
resCenter = i;
}
}
resLen = resLen - 1;
int start = (resCenter - resLen) >> 1;
return s.substring(start, start + resLen);
}

|