POJ 3974:Palindrome
Description
Andy是计算机系的非常聪明的一个学生,她参加了一门算法课,教授问了学生一个简单的问题:“你能不能高效地在一个字符串中找到最长回文子串呢?”。
如果一个字符串从前往后读和从后往前读是一样的,则字符串被称为是回文。比如“madam”是回文,而“acm”不是回文。
学生意识到这是一个经典的问题,但是他们只能够想到列举所有的子串并且判断这个子串是不是回文,很明显这个算法并不高效,这时Andy举手说:“我有一个更好的算法”,在他开始解释他的思想之前他停了一会,并说:“我有了一个更好的算法”。
如果你认为你知道Andy的最后解决方案,那么解决他吧。给定一个长度至多为1,000,000 字符串,输出最长回文子串的长度。
Input
你的程序将会被至多30个测试用例测试,每个测试用例是每行一个长度至多1000000的小写字符串。输入终止于字符串“END”。
Output
每个测试用例都输出测试用例的编号和最长回文子串的长度。
Sample Input
abcbabcbabcba abacacbaaaab END
Sample Output
Case 1: 13 Case 2: 6
Source
Manacher算法即可在 O(n) 时间内找到最长回文子串,这里要注意是求“Longest Palindrome Substring” 而不是 “Longest Palindrome Subsequence”。
1 import java.util.Scanner; 2 3 public class Main { 4 public static int longestPalidromeSubstring(String str){ 5 char[]t = preprocess(str); 6 int p[] = new int[t.length]; 7 int center = 0; 8 int right = 0; 9 int mirror = 0; 10 for(int i=1;i<t.length-1;i++){ 11 mirror = 2*center - i; 12 if(right>i){ 13 p[i] = Math.min(right - i, p[mirror]); 14 } 15 while(t[i+(1+p[i])]==t[i-(1+p[i])]){ 16 p[i]++; 17 } 18 if(i+p[i]>right){ 19 center = i; 20 right = i+p[i]; 21 } 22 } 23 int max = 0; 24 for(int i=1;i<t.length-1;i++){ 25 if(p[i]>max) max = p[i]; 26 } 27 return max; 28 } 29 private static char[] preprocess(String str) { 30 char[] ch = new char[2*str.length()+ 3]; 31 ch[0] = '$'; 32 ch[2*str.length()+2] = '@'; 33 for(int i=0;i<str.length();i++){ 34 ch[2*i+1] = '#'; 35 ch[2*i+2] = str.charAt(i); 36 } 37 ch[ch.length-2] = '#'; 38 return ch; 39 } 40 public static void main(String[] args) { 41 Scanner in = new Scanner(System.in); 42 String line = null; 43 int count = 0; 44 while(!(line=in.nextLine()).equals("END")){ 45 System.out.println("Case "+(++count)+": "+longestPalidromeSubstring(line)); 46 } 47 } 48 }