Leetcode之最長迴文子串
阿新 • • 發佈:2020-09-10
問題描述
給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為 1000。
示例 1:
輸入: "babad"
輸出: "bab"
注意: "aba" 也是一個有效答案。
示例 2:
輸入: "cbbd"
輸出: "bb"
解法
思路很簡單,首先想到若情況為迴文字串奇數個字元時,中間的字元為軸。比較兩邊的字元是否相同。當迴文串字元為偶數時,剛開始假想它以空氣為軸,則找不到其他字元的下標。於是想到在每個字元包括兩邊都插入一個特殊字元比如(),這樣構成的迴文字串一定是奇數長度。也就是一定存在中間的某個字元,使得兩邊以它(可能是特殊字元也可能原字串中的字元)為軸,並且此字串的兩邊都以
結尾。
public static void longestPalindrome(String s) { //在每兩個字元中間插入特殊字元,保證迴文字串一定是奇數長度 String str=s.replace("", "*"); int maxl=1; int index=0; //從左到右遍歷,尋找以每一個字元為軸的最大長度 for(int i=1;i<str.length();i++) { if(maxl<=2*Math.min(i,str.length()-i-1)+1) {//兩邊的長度可以超過最大長度 for(int j=1;;j++) { if(j<=i&&j<=str.length()-i-1) {//兩邊的長度可以取到的值 if(str.charAt(i-j)!=str.charAt(i+j)) {//這一個字元不是迴文串中的 int l=2*j-1; if(maxl<l) { maxl=l; index=i; } break; } }else {//到頭了都是迴文串 int l=2*j-1; if(maxl<l) { maxl=l; index=i; } break; } } } } //得到字串 StringBuilder sb=new StringBuilder(); for(int i=index+1-(maxl-1)/2;i<=index-1+(maxl-1)/2;i++) { if(i%2!=0) { sb.append(str.charAt(i)); } } }
結果
官方解法
方法一 動態規劃
使用P[i][j]表示Si到Sj是否是一個迴文串。
動態規劃轉移方程可以寫為P[i][j]=P[i+1][j-1]&Si,即先看中間再加上首尾兩端。
邊界條件:因為單個的字元為迴文串,P[i][i]=true,兩個相鄰的相同字元為迴文串if Si==Si+1則P[i][i+1]=true
根據這個思路我自己寫了一個程式碼。跑出來的效果很差。
public static String longestPalindrome(String s) { if(s==null||s.isEmpty()) return ""; boolean[][]P=new boolean[s.length()][s.length()]; //邊界 int length=1; int start=0,end=0; for(int i=0;i<s.length()-1;i++) { if(s.charAt(i)==s.charAt(i+1)) { P[i][i+1]=true; if(length<2) { length=2; start=i; end=i+1; } } P[i][i]=true; } P[s.length()-1][s.length()-1]=true; // for(int i=0;i<s.length()-2;i++) { for(int j=0;j<s.length()-i-2;j++) { if(P[j+1][j+i+1]&&s.charAt(j)==s.charAt(j+i+2)) { P[j][i+j+2]=true; int l=i+3; if(length<l) { length=l; start=j; end=i+j+2; } } } } s=s.substring(start, end+1); return s; }
方法二 中心擴充套件
方法二的本質即為:我們列舉所有的「迴文中心」並嘗試「擴充套件」,直到無法擴充套件為止,此時的迴文串長度即為此「迴文中心」下的最長迴文串長度。這個演算法思想與我的很相似。但是跑出來的效果比我好。
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expandAroundCenter(s, i, i);
int len2 = expandAroundCenter(s, i, i + 1);
int len = Math.max(len1, len2);
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substring(start, end + 1);
}
private int expandAroundCenter(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;
}
}
方法三 Manacher演算法
略