题目
求最长的回文子串。这道题的最优解法当然是马拉车算法。
首先要说一下最基本的方法。最暴力的就不说了,太费时间。稍微暴力一点的就是:以每个位置为中心向两侧扩展,看看能够扩出多长的子串。但是这里就面临一个问题。就是回文串分为奇回文和偶回文。这样在代码上倒是可以实现,需要分为两种情况来扩展。1.把当前点作为奇回文的中心,2.把当前点和前面一个点作为偶回文的第一对回文字符。这样子再去暴力扩展。
而manacher算法的优化其实就是优化了暴力扩展中的一些重复的工作。
首先,在字符串的首尾和每个字符之间都加上一个特定的字符‘#’。这样操作之后,所有的回文串都会变为奇回文,省去了分情况的麻烦。
然后是,用c来记录当前回文中心的位置,r记录当之前所有回文半径扩到的位置,p[]来记录每个位置的回文半径。
当前到达的位置i,如果i并没有处于r所扩到的位置,则记录i位置的回文半径为1,当前位置需要继续向两边扩充比较。
如果i处于r所扩充的位置内,需要看i点关于r的回文中心的对称点j,来看一下j点的回文半径大小如何?如果没有超出r扩出的范围,那么i的回文半径等于j的回文半径。如果超出了,i的回文半径就等于i到r的长度。如果正好压线,那么i的回文半径暂时等于i到r的长度,需要继续向外扩充比较。
class Solution {
public String longestPalindrome(String s) {
if(s==null || s.length()==0) return s;
char[] charArr = manacherString(s);
int[] p = new int[charArr.length];
int c = -1;
int r = -1;
int max = Integer.MIN_VALUE;
int result = 0;
for(int i=0;i!=charArr.length;i++){
p[i] = r>i?Math.min(p[2*c-i],r-i):1;
while(i+p[i]<p.length && i-p[i]>-1){
if(charArr[i-p[i]]==charArr[i+p[i]]){
p[i]++;
}else{
break;
}
}
if(i+p[i]>r){
r = i+p[i];
c = i;
}
if(p[i]>max){
result = i;
max = p[i];
}
}
String s1 = "";
for(int i=result+1-max;i<result+max;i++){
if(charArr[i]!='#') s1+=charArr[i];
}
return s1;
}
public static char[] manacherString(String s){
char[] chr = s.toCharArray();
char[] res = new char[chr.length*2+1];
int index = 0;
for(int i=0;i<res.length;i++){
res[i] = (i&1)==0?'#':chr[index++];
}
return res;
}
}
爷要哭了,总是记不住这个算法的细节。。。
发现个特牛逼的动态规划,说白了动态规划就是申请开辟一块空间,然后把过程中的一些量值记录下来,这样再查找使用的时候就会比较快速和方便。
dp[i][j]=1代表i到j位置的字符串为回文字串,因此就可以通过判断s[i+1]和s[j-1]是否相同,以及dp[i+1][j-1]是否为1.
class Solution {
public String longestPalindrome(String s) {
if(s.isEmpty()) return "";
int len = s.length();
if(len==1) return s;
char[] num = s.toCharArray();
int[][] dp = new int[len][len];
int start = 0;
int longest = 1;
for(int i=0;i<len;i++){
dp[i][i] = 1;
if(i<len-1){
if(num[i]==num[i+1]){
dp[i][i+1] = 1;
start = i;
longest = 2;
}
}
}
for(int l = 3;l<=len;l++){
for(int i = 0;i<len-l+1;i++){
int j = i+l-1;
if(num[i]==num[j] && dp[i+1][j-1]==1){
dp[i][j] = 1;
start = i;
longest = l;
}
}
}
return s.substring(start,start+longest);
}
}