题目:
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
分析:
该题使用Manacher算法,首先为了避免字符串个数成奇数或偶数的问题,在每个字符两边加上字符串不存在的符号,我这使用了#,还有为了防止判断字符串为回文串是向两边延伸时出现数组溢出异常,在首尾两头可以加上不同的字符,并且首尾两新增字符不参与是否回文串判断。
本算法的核心是:
if (maxid > i) {
longest[i] = Math.min(longest[2 * id - i], maxid - i);
} else {
longest[i] = 1;
}
这是考虑到回文字符串的对称性,首先定义了id,maxid两个变量,定义一个最终对称点位置变量longestStr和以该对称点为位置的最长回文串长度。id就是指前一次非1长度回文串的对称点,maxid就是该对称点的最长延伸(maxid=id+longest[id]-1)(longest[i]表示以i点为对称点的回文字符串半径)。遍历字符串,当maxid>i表示当前点在前一次回文字符串内,然后我们就可以找到当前点关于id的对称点2*id-i,根据对称性,i与2*id-i点的回文串半径在基于前一次回文串内是相同的,但是考虑到i+longest[2*id-i]会超出maxid,所以利用min(2*id-i,maxid-i)加以限制。
代码:
public class Solution {
public String longestPalindrome(String s) {
String strs = newString(s).toString();
char[] str = strs.toCharArray();
int[] longest = new int[strs.length()];
int id = 0, maxid = 0;
int maxLongest = 0;
int longestStr = 0;// 最终对称点位置
for (int i = 0; i < str.length; i++) {
if (maxid > i) {
longest[i] = Math.min(longest[2 * id - i], maxid - i);
} else {
longest[i] = 1;
}
while (0 < i && i < str.length - 1 && str[i + longest[i]] == str[i - longest[i]]) {//首尾两头不进行比较
longest[i]++;
}
if (longest[i] + i - 1> maxid) {
maxid = longest[i] + i - 1;
id = i;
}
if (maxLongest < longest[i]) {
maxLongest = longest[i];
longestStr = i;
}
}
String longString = strs.substring(longestStr - longest[longestStr] + 1, longestStr + longest[longestStr]);
return longString.replace("#", "").trim();
}
public StringBuffer newString(String s) {
char[] str = s.toCharArray();
StringBuffer sb = new StringBuffer();
sb.append("@#");
for (int i = 0; i < str.length; i++) {
sb.append(str[i]).append("#");
}
sb.append("$");
return sb;
}
}