方法一:马拉车算法
时间复杂度O(n)
这个算法最为关键的一行
r[i] = mx > i ? Math.min(r[2 * id - i], mx - i) : 1;
具体讲解传送门。
基本上理解了这句·就差不多懂了90%
最后根据找到的最大回文中心点以及对应半径来正确的得到回文子串。
下面是LeetCode上面的AC代码:(Java)
class Solution {
public String longestPalindrome(String s) {
if(s==null||s.length()<=1)
return s;
StringBuilder sb=new StringBuilder("$#");
int i;
for(i=0;i<s.length();i++){
sb.append(String.valueOf(s.charAt(i)));
sb.append("#");
}
String str=sb.toString();
int[] r=new int[str.length()];
int mx=0,id=0,ansR=0,ansCenter=0;
for(i=1;i<str.length();i++){
r[i]=mx-i>r[i]?Math.min(r[2*id-i],mx-i):1;
while(((i-r[i])>=0)&&((i+r[i])<str.length())
&&str.charAt(i-r[i])==str.charAt(i+r[i]))
r[i]++;
if(i+r[i]>mx){
mx=i+r[i];
id=i;
}
if(ansR<r[i]){
ansR=r[i];
ansCenter=i;
}
}
int maxStart=(ansCenter-ansR+1)/2;
if(maxStart>=0)
return s.substring(maxStart,maxStart+ansR-1);
return "";
}
}
方法二 :中心扩展法
时间复杂度O(n^2)
class Solution {
public String longestPalindrome(String s) {
if(s==null||s.length()<=1)
return s;
int start=0,end=0;
for(int i=0;i<s.length();i++){
int len=Math.max(func(s,i,i),func(s,i,i+1));
if(len>end-start){
start=i-(len-1)/2;
end=i+len/2;
}
}
return s.substring(start,end+1);
}
public int func(String s,int left,int right){
int l=left,r=right;
while(l>=0&&r<s.length()
&&s.charAt(l)==s.charAt(r)){
l--;
r++;
}
return r-l-1;
}
}
方法三:动态规划
时间复杂度:o(n^2)
class Solution {
public String longestPalindrome(String s) {
if(s==null||s.length()<=1)
return s;
boolean dp[][]=new boolean[s.length()][s.length()];
int max=0,start=0,end=0;
for(int i=0;i<s.length();i++)
for(int j=0;j<=i;j++){
if(s.charAt(i) == s.charAt(j) && (i - j < 2 || dp[j+1][i-1])) {
dp[j][i] = true;
}
if(dp[j][i] && max < i - j + 1) {
max = i - j + 1;
start = j;
end = i;
}
}
return s.substring(start, end + 1);
}
}