編程之法:面試和算法心得(最長回文子串)
阿新 • • 發佈:2018-01-03
高效 pre 記錄 特殊字符 一段 stp ace 分開 枚舉
內容全部來自編程之法:面試和算法心得一書,實現是自己寫的使用的是java
題目描述
給定一個字符串,求它的最長回文子串的長度。
分析與解法
最容易想到的辦法是枚舉所有的子串,分別判斷其是否為回文。這個思路初看起來是正確的,但卻做了很多無用功,如果一個長的子串包含另一個短一些的子串,那麽對子串的回文判斷其實是不需要的。
解法一
那麽如何高效的進行判斷呢?我們想想,如果一段字符串是回文,那麽以某個字符為中心的前綴和後綴都是相同的,例如以一段回文串“aba”為例,以b為中心,它的前綴和後綴都是相同的,都是a。
那麽,我們是否可以可以枚舉中心位置,然後再在該位置上用擴展法,記錄並更新得到的最長的回文長度呢?答案是肯定的,參考代碼如下:
/* * 枚舉中心位置,然後再在該位置上用擴展法,記錄並更新得到的最長的回文長度 */ public static int longestPalindrome1(String s) { int evenMaxlength=0; int oddMaxlength = 0; //長度為奇數 for(int i=0;i<s.length();i++) { int j=i-1; int k=i+1; int temp=1;while(j>=0&&k<s.length()&&s.charAt(j)==s.charAt(k)) { temp = temp+2; j--; k++; } oddMaxlength = oddMaxlength>temp?oddMaxlength:temp; } //長度為偶數 for(int i=0;i<s.length();i++) {int j=i; int k=i+1; int temp=0; while(j>=0&&k<s.length()&&s.charAt(j)==s.charAt(k)) { temp = temp+2; j--; k++; } evenMaxlength = evenMaxlength>temp?evenMaxlength:temp; } return oddMaxlength>evenMaxlength?oddMaxlength:evenMaxlength; }
解法二、O(N)解法
在上文的解法一:枚舉中心位置中,我們需要特別考慮字符串的長度是奇數還是偶數,所以導致我們在編寫代碼實現的時候要把奇數和偶數的情況分開編寫,是否有一種方法,可以不用管長度是奇數還是偶數,而統一處理呢?比如是否能把所有的情況全部轉換為奇數處理?
答案還是肯定的。這就是下面我們將要看到的Manacher算法,且這個算法求最長回文子串的時間復雜度是線性O(N)的。
首先通過在每個字符的兩邊都插入一個特殊的符號,將所有可能的奇數或偶數長度的回文子串都轉換成了奇數長度。比如 abba 變成 #a#b#b#a#, aba變成 #a#b#a#。
/* * 在裏面添加特殊字符。添加了“#”,使abba變為a#b#b#a */ public static int longestPalindrome2(String s) { StringBuffer s1 = new StringBuffer(s); int length=s1.length(); for(int i=0,k=1;i<length-1;i++)//給字符串添加 # { s1.insert(k,"#"); k=k+2; } s = s1.toString(); String temp = ""; int max = 0; for(int i=0;i<s.length();i++) { int j=i-1; int k=i+1; int maxtemp = 1; String maxString = Character.toString(s.charAt(i)); while(j>=0&&k<s.length()&&s.charAt(j)==s.charAt(k)) { maxtemp = maxtemp+2; maxString = Character.toString(s.charAt(j))+maxString+Character.toString(s.charAt(k)); j--; k++; } if(max<maxtemp) { max = maxtemp; temp = maxString; } } temp = temp.replaceAll("#", ""); return temp.length(); }
編程之法:面試和算法心得(最長回文子串)