标签:
本文是LeetCode题库的第五题,没想到做这些题的速度会这么慢,工作之余全部耗在这上面了,只怪自己基础差。本文主要介绍使用Manacher线性算法来求解字符串的最长回文子字符串。
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.
1 public char[] expandString(String s){
2 int len = s.length();
3 char[] cs = new char[len*2+3];
4 for(int i = 0; i < len; i++){
5 cs[2*i+1]=‘#‘;
6 cs[2*i+2]=s.charAt(i);
7 }
8 cs[0]=‘*‘;
9 cs[2*len+1]=‘#‘;
10 cs[2*len+2]=‘?‘;
11 return cs;
12 }
13 public String shrinkString(char[] cs){
14 int len = cs.length;
15 char [] shrinkChars = new char[len];
16 int j=0;
17 for(int i = 0; i < len;i++){
18 if (cs[i] != ‘#‘){
19 shrinkChars[j++] = cs[i];
20 }
21 }
22 return new String(shrinkChars).trim();
23 }
public String longestPalindrome(String s) {
char[] cs = expandString(s);
int len = cs.length;
int [] p = new int[len];
int max = 0;
for(int i = 1; i <len-1 ; i++){
p[i]=1;
while(cs[i+p[i]]==cs[i-p[i]]) p[i]++;
if (p[i] > p[max]){
max = i;
}
}
int lenMax = p[max];
char [] result = new char[2*lenMax-1];
result[lenMax-1] = cs[max];
for(int i = 1 ; i < lenMax ; i++){
result[i+lenMax-1] = cs[max+i];
result[lenMax-1-i] = cs[max+i];
}
return shrinkString(result);
}
具体的Manacher线性算法详见《最长回文子串(Longest Palindromic Substring)》。
利用一个辅助数组 arr[n],其中 arr[i] 记录的是以 str[i] 为中心的回文子串长度。当计算 arr[i] 的时候,arr[0...i-1] 是已知并且可被利用的。Manacher 核心在于:用 mx 记录之前计算的最长的回文子串长度所能到达的最后边界,用 id 记录其对应的中心,可以利用回文子串中的回文子串信息。
假设 id 与 mx 已经得出,当计算以 str[i] 为中心回文子串长度时,因为已经可以确定绿色部分已经是回文子串了,所以可以利用以 str[j] 为中心回文子串长度即 arr[j]。在上图的情况下,所以可以从箭头所指出开始比较。还有一种情况:
这种情况下,不能直接利用以 str[j] 为中心回文子串长度即 arr[j],因为以 id 为中心回文子串长度只计算到了绿色箭头所指之处,所以能力利用的信息是 mx-i,比较 mx-i 之后的字符。
Manacher算法代码如下:
1 public String longestPalindromeOne(String s) { 2 3 char[] cs = expandString(s); 4 int len = cs.length; 5 int [] p = new int[len]; 6 int id = 0; 7 int max = 0; 8 for(int i = 1; i <len-1 ; i++){ 9 if (i < p[id]+id){ 10 p[i]=Math.min(p[id]+id-i, p[2*id-i]); 11 }else{ 12 p[i]=1; 13 } 14 15 while(cs[i+p[i]]==cs[i-p[i]]) p[i]++; 16 17 if( p[i]+i> p[id]+id ){ 18 id = i; 19 } 20 21 if (p[i] > p[max]){ 22 max = i; 23 } 24 25 } 26 27 int lenMax = p[max]; 28 char [] result = new char[2*lenMax-1]; 29 result[lenMax-1] = cs[max]; 30 for(int i = 1 ; i < lenMax ; i++){ 31 result[i+lenMax-1] = cs[max+i]; 32 result[lenMax-1-i] = cs[max+i]; 33 } 34 35 return shrinkString(result); 36 }
关于Manacher算法要补充说明一下几点:
LeetCode(4) || Longest Palindromic Substring 与 Manacher 线性算法
标签:
原文地址:http://www.cnblogs.com/rcfeng/p/4328615.html