题目
Given a string s ,find the longest palindromic in s .You may assume that maximum length of s is 1000,and there exists one unique longest palindromic substring.
题意
求一个给定字符串S的最长回文串,其中回文串指的是可以从串中间向两边扩展的字符串均相等。
思路
manacher算法:
-
由于字符串的长度有可能是奇数也有可能是偶数,所以为了统一处理奇偶情况,需要对字符串进行一个预处理。
abbaabb -> #a#b#b#a#a#b#b#
-
定义一个大小与预处理之后的字符串大小相同的数组,用来保存以该位置的字符为回文中心产生的回文半径
abcdcb
以第四个位置字符d为中心的回文半径为2,则res[4] = 4
-
res[]数组的生成方法:对于当前位置i,求回文半径大小。此时i前面位置的回文半径都已经求出了,回文半径扩展到最右边的位置为C ,回文半径为R
1: 判断i的对称点j,如果res[j]的回文左边缘在 C 的回文左边缘的右边,即2代表的大括号为j的整个回文在C所代表的回文之中,由于C本身是回文,所以res[i] = res[j];
2: 如果j的回文超出了C的回文,即1包括的字符串,则此时对应的i的回文串至少包含了C的一部分,剩下的部分需要判断idx2位置与idx1位置的字符串是否相等;然后idx2一直向右,idx1一直向左,直到不相等为止,即得到i的回文半径。若回文半径边缘超出了R,则需要更新C=i,R=i + res[i]。
3: 如果i没有对称点,则需要则需要将i的前后一一比对,这个可以与2放到一起进行。
代码
package Leetcode;
import java.util.Scanner;
//寻找最长回文串
public class lc5 {
static Scanner sc = new Scanner(System.in);
static String s = sc.next();
static char[] b = s.toCharArray();
static char a [] = new char[2001];
static int r[] = new int[2001];
static int w = 2*s.length()+1;
public static void main(String[] args) {
int i;
for (i = 0;i<s.length();i++){
a[2*i] = '#';
a[2*i+1] = b[i];
}
a[2*i] = '#';
r[0] = 1;
int c = 0,R = r[c];
for (i = 1;i<w;i++){
int j = c-(i-c);
if (j<=c-R){
r[i] = function(i,1);
}else{
if (j-r[j]<c-R){
r[i] = c+R-i;
r[i] = function(i,r[i]);
}else
r[i]=r[j];
}
}
int max = -1;
for (i = 0;i<w;i++){
if (max<r[i])
max = r[i];
}
for (i=0;i<w;i++){
if (r[i] == max)
break;
}
for (int j=i-r[i]+1;j<i+r[i]-1;j++){
if (j%2!=0)
System.out.print(a[j]);
}
}
public static int function(int i,int r){
while (true){
if (i+r >=w )
return r;
if (i-r<=-1)
return r;
if (a[i+r] == a[i-r])
r++;
else
return r;
}
}
}