最近在leetcode上刷题,看到的Longest Palindromic Substring问题,leetcode上给出了5种方法(暴力法、最长公共子串法、DP、中心扩展法)+Manacher算法。5种方法中Manacher算法是唯一一个可以在O(N)时间复杂度内求解最长回文子串的算法。leetcode官方解答没有给出算法的描述,后面搜索了网上的博客资源,才看懂。
整理Manacher算法,主要是出于两点:1、惊叹于算法的巧妙;2、记录自己实现中遇到的一些问题,希望有机会跟各位进行交流。
1)算法的详细过程与精妙之处,网上的大牛已经进行了详尽的整理。在此,不再赘述!推荐大家参照:
Manacher算法:求解最长回文字符串,时间复杂度为O(N)
2)重点整理自己在实现过程中的疑问。
在上述的博文中,作者都之处为了防止越界,在初始化的过程中分别在字符串首部和尾部插入“$”及“\0”。但是在笔者自己实现的过程中,发现:字符首部和尾部特意插入“$”及“\0”并不是必须的!
话不多说,代码附上!(代码写的比较挫,大家凑合看)
public class Solution {
public String longestPalindrome(String s) {
int len = s.length();
len = 2 * len + 1;
//initialization
char array[] = new char[len];
//array[0] = '$';
for(int i = 1, j = 0; i < len; j++, i = i + 2){
array[i] = s.charAt(j);
array[i-1] = '#';
}
array[len - 1] = '#';
//algorithm
int mx = 0;
int id = 0;
int p[] = new int[len];
for(int i = 0; i < len; i ++){
if( i < mx){
p[i] = p[2*id - i] < mx - i ? p[2*id - i]: mx - i;
}else{
p[i] = 1;
}
for(; (i + p[i] < len ) && ( i - p[i] >= 0) && (array[i + p[i]] == array[i - p[i]]); p[i]++){
}
if( i + p[i] > mx){
mx = i+p[i];
id = i;
}
}
//max rad
int rad = 1;
int mid = 0;
for(int i = 0; i < len ; i++){
if(p[i] > rad){
mid = i;
rad = p[i];
}
}
char res[] = new char[ rad - 1];
int num = 0;
for( int i = mid - rad + 1; i < mid + rad - 1; i++){
if(array[i] != '#'){
res[num++] = array[i];
}
}
String subs = new String(res);
return subs;
}
}