最长回文子字符串问题:给定一个字符串,找出字符串中的最长的回文子字符串
思路一,暴力破解
找出所有的回文子字符串,找出其中最长的字符串
代码:
public static String longestPalindrome(String s) {
for(int i=s.length()-1;i>=0;i--) {
for(int j=0;i+j<s.length();j++) {
if(isPalindrome(s.substring(j,i+j+1)))
return s.substring(j,i+j+1);
}
}
return null;
}
private static boolean isPalindrome(String temp) {
for(int i=0,j=temp.length()-1;j>=i;i++,j--) {
if(temp.charAt(i)!=temp.charAt(j))
return false;
}
return true;
}
时间复杂度是O(N^3),太过于复杂。
思路二,动态规划
对于一个回文字符串,将其最左边与最右边的字符去掉,得到的子串仍然是回文字符串。发现这种规律,可以考虑使用动态规划。重复上述的“除去最左端最右端的字符得到子字符串”这个过程,最后会得到边界条件:如果是奇回文字符串,最后的边界条件是单个的字符;如果是偶回文字符串,最后的边界条件是两个挨着的相同的字符。我们使用一个二维矩阵来记录某段子串是否是回文字符串。
代码:
public String longestPalindrome(String s) {
int N=s.length();
if(N==0) return null;
int max=1;
int start=0;
boolean[][] p=new boolean[N][N];
for(int i=0;i<N;i++) {
p[i][i]=true;
}
for(int i=0;i<N-1;i++) {
if(s.charAt(i)==s.charAt(i+1)) {
p[i][i+1]=true;
max=2;
}
}
for(int len=3;len<=N;len++) {
for(int j=0;j+len<=N;j++) {
if(s.charAt(j)==s.charAt(j+len-1)&&p[j+1][j+len-2]==true) {
p[j][j+len-1]=true;
if(len>max) {
max=len;
start=j;
}
}
}
}
return s.substring(start, start+max);
}
时间复杂度是O(N^2),这种复杂度如果处理特别长的字符串也会消耗大量的时间
思路三,Manacher算法
针对回文字符串的处理,在1975年的时候,Manacher提出了专门的Manacher算法,它的思路是,结合之前已经鉴别出来的回文字符串,鉴别出后面的回文字符串。但是这种算法只对奇回文字符串起作用,为了能够鉴别偶回文字符串,我们可以在字符串的首尾以及字符之间插入特殊字符,经过这样处理之后,偶回文字符串变成了奇回文字符串,而奇回文字符串仍然是奇回文字符串。
id是已经找到的回文字符串的对称中心点,Right是右边界,left是左边界,在数组p[]中保存id的回文半径,j是i关于id的对称点,若i<Right,则p[i]=Math.min(Right-i, p[j]),否则p[i]=1。对p[i]进行初始化以后,以i为中心,对i的回文半径p[i]进行更新。更新完毕后,如果i+p[i]>Right,则对Right和id进行更新。
代码:
public String longestPalindrome(String s) {
StringBuffer temp=new StringBuffer();
temp.append("&");
for(int i=0;i<s.length();i++) {
temp.append("#");
temp.append(s.charAt(i));
}
temp.append("#");
int[] p=new int[temp.length()];
int id=-1,right=-1;
for(int i=1;i<temp.length();i++) {
if(i<right) {
p[i]=Math.min(right-i, p[2*id-i]);
}
else
p[i]=1;
while((i+p[i])<temp.length()&&(i-p[i])>=0&&temp.charAt(i+p[i])==temp.charAt(i-p[i])) {
p[i]++;
}
if(i+p[i]>right) {
right=i+p[i];
id=i;
}
}
int max=0,idx=0;
for(int i=0;i<temp.length();i++) {
if(p[i]>max) {
max=p[i];
idx=i;
}
}
return s.substring((idx-max)/2, (idx+max)/2-1);
}
时间复杂度是O(N)