题目描述: 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
1.O(n^2)解法:
①定义一个二维辅助数组p,其中p[i][j]的含义:p[i][j] = s.substring(i,j+i) 是否是回文子串?1:0;
②初始情况:当i=j时,p[i][j] = 1; 当i=j-1时,p[i][j] = s[i]==s[j]?1:0;
③那么,现在的问题就是根据初始情况,来求p[i][j]了。根据回文串的特性,只有当p[i+1][j-1]为回文串时且s[i]=s[j]时,p[i][j]才是回文串;否则,p[i][j]不满足回文串特性。
④求得辅助数组p后,可求得回文子串中的最长回文串。
代码如下:
//最长回文子串
public String longestPalindrome(String s) {
int[][] dp = new int[s.length()][s.length()];
int max_length = -1;
int start = -1;
int end = -1;
for(int j=0;j<s.length();++j){
for(int i = 0;i<=j;++i){
if(i==j){
dp[i][j] = 1;
}
else if(i==j-1){
if(s.charAt(i)==s.charAt(j))
dp[i][j] = 1;
}
else if(dp[i+1][j-1]==1){
if(s.charAt(i)==s.charAt(j)){
dp[i][j] = 1;
}
}
if(dp[i][j]==1){
if(max_length<s.substring(i,j+1).length()){
start = i;
end = j+1;
max_length = s.substring(start,end).length();
}
}
}
}
if(start>=0)
return s.substring(start,end);
return "";
}
2.Manacher 算法:具体思路可以点标题进去看,感觉这篇是我看到的讲得比较清晰的。
实现代码:
//最长回文子串 Manacher 算法
public String Manacher(String s) {
//奇偶处理
char[] chars = new char[s.length()*2+3];
chars[0] = '^';
chars[s.length()*2+2] = '$';
int j = 1;
for(int i=0;i<s.length();++i){
chars[j++] = '#';
chars[j++] = s.charAt(i);
}
chars[j] = '#';
int[] p = new int[chars.length];
p[0] = 0;
p[1] = 0;
int Mi = 1;
for(int i=2;i<chars.length-1;++i){
int L = Mi-p[Mi];
int R = Mi+p[Mi];
if(i<R){
j = 2*Mi-i;
if(j-p[j]>L){
p[i] = p[j];
}else{
p[i] = R-i-1;
int ir = R;
int il = 2*i-R;
while(ir>0&&ir<chars.length-1){
if(chars[ir]==chars[il]){
p[i]++;
ir++;
il--;
}else{
break;
}
}
}
}else{
//按传统方法求解
int il = i-1;
int ir = i+1;
while(ir>0&&ir<chars.length-1){
if(chars[ir]==chars[il]){
p[i]++;
ir++;
il--;
}else{
break;
}
}
}
if(p[i]>p[Mi])
Mi = i;
}
StringBuilder sb = new StringBuilder();
for(int start = Mi-p[Mi];start<=Mi+p[Mi];++start){
if(chars[start]!='#'){
sb.append(chars[start]);
}
}
return sb.toString();
}