最長迴文子串問題,題目描述:給定一個字符串 s
,找到 s
中最長的迴文子串。你可以假設 s
的最大長度爲 1000。
所謂迴文串,就是指一個字符串正序和倒序完全一致,必須"aba","baab"等,本題求的是一個字符串最長的迴文子串,比如"aabbaccddcc"的最長迴文子串就是"ccddcc"。
首先想到的是暴力解法,遍歷每一個字符作爲子串的開端,字符串從後往前的每一個字符作爲子串的結尾,然後再進行迴文串的判斷,因爲要進行三次循環,所以總的時間複雜度爲,結果超時,但扔然通過93個測試樣例。
暴力法的思路是從兩端向中間找出所有的迴文子串,這樣必然存在大量的重複對比,比如"abdcfdba",a對比了一次,b對比了兩次,d對比了三次,明顯不合理。
優化暴力方法的思路就是動態規劃,動態規劃的核心思想就是大問題化爲小問題來解決 ,假如已知某子串s1爲迴文串,比如"abba",那麼s加上前一位和向後一位的新子串s2爲迴文串的條件就是加的這兩個字符相同,比如"cabbac",描述如下(截圖)。
因此需要一個二維數組來存儲的值 ,依次求出長度爲1到N(字符串長度)的子串是否爲迴文串,其中1和2需要單獨判斷,3到N利用動態方程求得,時間複雜度爲,缺點是需要額外的空間存儲二維數組,長字符串會有較大開銷,實現代碼如下。
class Solution {
public String longestPalindrome(String s) {
int length = s.length();
Boolean p[][] = new Boolean[length][length];
int maxlen = 0;
int start=0,end=0;
for(int len = 1 ; len <= length ; ++len)
for(int i = 0; i< length ; ++i)
{
int j = i+len-1;
if(j>=length)
break;
p[i][j] = (len==1||len==2||p[i+1][j-1])&&s.charAt(i)==s.charAt(j);
if(p[i][j]&&len>maxlen)
{
start = i;
end = j;
maxlen = len;
}
}
return length>1?s.substring(start,end+1):s;
}
}
另一種思路就是從中間向兩端查找,也就是遍歷每一個字符作爲迴文子串的中間點,然後向兩邊對比,這樣的時間複雜度爲。由於迴文子串的中心可以是一個字符,也可以是兩個字符,所以要分別處理。這種方法也叫做中心擴展法,實現代碼如下。
class Solution {
public String longestPalindrome(String s) {
int length = s.length();
if(length<2)
return s;
int start = 0, end = 0, maxlen = 0;
for(int i = 0;i < length;++i)
{
int lenOdd = expandCenter(s,i, i);
int lenEven = expandCenter(s,i, i+1);
int len = Math.max(lenOdd,lenEven);
if(len>maxlen)
{
maxlen = len;
start = i-(len-1)/2;
end = i+len/2;
}
}
return s.substring(start,end+1);
}
public int expandCenter(String s,int L,int R)
{
int len = (L==R?-1:0);
while(L>=0&&R<s.length())
{
if(s.charAt(L)!=s.charAt(R))
break;
len+=2;
L--;
R++;
}
return len;
}
}