using Java; Manacher’s Algorithm;O(N)
题目
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
难度
medium(难点主要在如何写一个时间复杂度O(n)的算法)
步骤
步骤主要参照简书:马拉车算法(Manacher’s Algorithm)
关键代码的理解(下面代码部分第21行)
p[j]=r>j?Math.min(p[2*c-j],r-j):1;
代码
class Solution {
public String longestPalindrome(String s) {
if (s.length() < 2) {
return s;
}
//r表示当前回文子串能延伸到的最右端的位置
//c表示r中回文子串的中心位置
//longj是指最长回文子串的中间位置
int c=0,r=-1,longj=0,maxLen=-1;
//在每两个字符间插入‘#’,同时在开头、结尾分别插入字符‘$’,‘@’
String t="$#";
for(int i=0;i<s.length();i++){
t=t+s.charAt(i)+"#";
}
t+="@";
int n=t.length();
//P数组保存以索引为中心位置的回文子串的最大半径
int[] p=new int[n];
for(int j=1;j<n-1;j++){
//这句话是核心!
p[j]=r>j?Math.min(p[2*c-j],r-j):1;
while(t.charAt(j+p[j])==t.charAt(j-p[j])){
p[j]++;
}
//更新当前回文子串能延伸到的最右端的位置
if(j+p[j]>r){
c=j;
r=j+p[j];
}
//更新maxLen;规律显示真正回文子串长度=加入'#'计算的半径-1
if(p[j]-1>maxLen){
longj=j;
maxLen=p[j]-1;
}
}
//根据规律计算最长回文子串开始的索引
int start = (longj-maxLen)/2;
return s.substring(start, start + maxLen);
}
}
注意点
- 为了方便最长回文子串的索引的计算,在每两个字符间插入‘#’, 同时在开头、结尾分别插入字符‘$’,‘@’
- 获得t字符串之后,循环开始结束条件分别是j=1和j<n-1,不把开头结尾插入的‘$’,‘@’计算在里面,不然会报错