Q:
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
A;
以下解法和代碼沒有借閱以往任何資料,如果有更好的解法請在評論區留言
這道題的大致意思是找出一個字符串中最長的迴文子串,給的字符串最大長1000,只有一個最長子串。
我拿到這道題的時候感覺跟之前一道題很像啊-我自己寫的LeetCode3,一個是求最長不重複串一個是求最長迴文串。上次的時間複雜度是O(n)。我在想是不是可以用二分法(也就是分治思想)變成O(logn)呢,不然這題做着是不是沒啥意思了。
首先我們肯定最後要把這個字符串分割成最小子串(長度爲1)返回他自己,然後父方法再查找自己,這樣就沒意思了,因爲子串和父串的最長重複子串之間沒有必然聯繫,最後還是要遍歷一下父串的,這樣算法最後複雜度還是O(nlogn),在評論裏求O(logn)解法。我這裏換一種思路去解O(n)解法了。
首先,迴文的性質如下:
1、迴文正讀和倒讀都是一樣的字符串
2、迴文串中心對稱
所以第一步可能我們需要先獲取所有迴文串然後找大小,如何確定一個字符串是迴文串呢?
關於中心對稱,但是我們如何快捷的找出這個中心對稱的字符串就是個難點。
我們考慮一下人是怎麼識別迴文串的。
1、讀取字符,在腦海中形成一種數據結構存儲我們讀取到的字符
2、對比都讀到的字符是不是和上一個或者上上個字符一致,如果一致繼續對比,直到不一致得出這是一個迴文串。
如果這種想法我們轉換成程序:
首先需要一個for來循環字符串這樣就是O(n)
其次需要另一個隱藏起來的循環來對比相似的字符串,這個複雜度怎麼算。。。好尷尬。
每一步只計算關於第一次發現重複位置的對稱位置是否一致的話這樣複雜度就成功到O(n)了。
來,讓我們寫個代碼看看(代碼比較複雜因爲寫了一個類進去)
public class LongestPalindromicSubstring {
public static void main(String[] args){
char[] m = "aaaaaa".toCharArray();
System.out.println(method(m));
}
private static char[] method(char[] m) {
// TODO Auto-generated method stub
Palindromic maxP = new Palindromic();
maxP.thisLength =0;
maxP.thisFlag =0d;
ArrayList<Palindromic> pList = new ArrayList<Palindromic>();
for(int i =1;i<m.length;i++){
if(i>=2){
if(m[i]==m[i-1]){//與相鄰的相等
Palindromic p = new Palindromic();
p.thisFlag = ((double)i+(double)i-1.0d)/2.0d;
p.thisLength =1;
pList.add(p);
}
if(m[i]==m[i-2]){//隔一個與上一個相等
Palindromic p = new Palindromic();
p.thisFlag = i-1.0d;
p.thisLength =1;
pList.add(p);
}
for(Palindromic p : pList){
if(!p.isEnd){
int symmetry =((int)p.thisFlag*2)-i;
if(m[i]==m[symmetry]){
p.thisLength++;
if(symmetry==0){
p.isEnd = true;
}
}else{
p.isEnd = true;
}
}
}
}else{
if(m[i]==m[i-1]){//與相鄰的相等
if(i==1){
Palindromic p = new Palindromic();
p.thisFlag = ((double)i+(double)i-1.0d)/2.0d;
p.thisLength = 1;
p.isEnd = true;
pList.add(p);
}else{
Palindromic p = new Palindromic();
p.thisFlag = ((double)i+(double)i-1.0d)/2.0d;
p.thisLength = 1;
pList.add(p);
}
}if(i==2&&m[i]==m[i-2]){//隔一個與上一個相等
System.out.println("ok");
Palindromic p = new Palindromic();
p.thisFlag = i-1.0d;
p.thisLength = 1;
pList.add(p);
}
}
}
for(Palindromic p: pList){
int length;
if(p.thisFlag/1.0d==0){
length = p.thisLength*2-1;
}else{
length = p.thisLength*2;
}
int maxlength;
if(maxP.thisFlag/1.0d==0){
maxlength = maxP.thisLength*2-1;
}else{
maxlength = maxP.thisLength*2;
}
if(length>maxlength){
maxP = p;
}
}
if(maxP.thisFlag/1.0d==0){
System.out.println(maxP);
return Arrays.copyOfRange(m, (int)maxP.thisFlag-maxP.thisLength-1, (int)maxP.thisFlag+maxP.thisLength);
}else{
System.out.println(maxP);
int flag = (int) Math.ceil(maxP.thisFlag);
return Arrays.copyOfRange(m,flag-maxP.thisLength , flag+maxP.thisLength);
}
}
static class Palindromic{
public double thisFlag = 0;
public int thisLength = 0;
public boolean isEnd = false;
@Override
public String toString() {
// TODO Auto-generated method stub
return "falg:"+thisFlag+"....."+"thisLength:"+thisLength;
}
}
雖然代碼量大,但是時間複雜度還可以,雖然沒有預期的O(n)雖然有兩層for嵌套,但是仔細算起來應該是趨近於O(n)這一種我也不會計算,因爲第二個for循環變量太多了。。。。