【探索-中級演算法】最長迴文子串
阿新 • • 發佈:2018-11-03
這一題可以參考:647. 迴文子串
本質上是一樣的,要判斷出所有的迴文字串,然後找到其中最長的那一個。
中心擴充套件法
中心擴充套件就是把給定的字串的每一個字母當做中心,向兩邊擴充套件,這樣來找最長的子迴文串。演算法複雜度為O(N^2)
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
char[] strs = s.toCharArray();
int len = strs.length;
int [] arr1 = new int[2];
int[] arr2 = new int[2];
//記錄起點與終點的位置
int start = 0, end = 0;
for (int i = 0; i < len; i++) {
//以 s(i) 為中心向兩邊擴散,得到最長的迴文子串
get(arr1, strs, i - 1, i + 1);
//以 s(i) 與 s(i+1) 為中心向兩邊擴散,得到最長的迴文子串
get(arr2, strs, i, i + 1);
int tmpStart, tmpEnd;
if (arr1[1] - arr1[0] > arr2[1] - arr2[0]) {
tmpStart = arr1[0];
tmpEnd = arr1[1];
} else {
tmpStart = arr2[0];
tmpEnd = arr2[1];
}
if ((tmpEnd - tmpStart) > (end - start)) {
start = tmpStart;
end = tmpEnd;
}
}
return s.substring(start, end + 1);
}
public void get(int[] arr, char[] strs, int left, int right) {
while (left >= 0 && right < strs.length && strs[left] == strs[right]) {
--left;
++right;
}
++left;
--right;
arr[0] = left;
arr[1] = right;
}
基於動態規劃
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
int len = s.length();
boolean dp[][] = new boolean[len][len];
char[] strs = s.toCharArray();
int start = 0, end = 0;
// 判斷 dp[i][i+1] 是不是迴文
for (int i = 0; i < len -1 ; i++) {
if(strs[i] == strs[i + 1]) {
dp[i][i + 1] = true;
start = i;
end = i + 1;
}
// dp[i][i] 即單個字母肯定是迴文
dp[i][i] = true;
}
//因為上面的迴圈無法設定最後一個字母,所以要在這裡設定
dp[len - 1][len - 1] = true;
// 按照 dp[i][j] = (dp[i + 1][j - 1] && (strs[i] == strs[j]))
// 的轉移方程來判斷 dp[i][j] 是不是迴文
// 如果是的話還要與原有最長的比較是不是更長且記錄
for (int i = len - 3; i >= 0; i--) {
for (int j = i+2; j < len; j++) {
dp[i][j] = (dp[i + 1][j - 1] && (strs[i] == strs[j]));
if (dp[i][j]) {
if (j - i > end - start) {
start = i;
end = j;
}
}
}
}
return s.substring(start, end + 1);
}
dp[i][j]
表示 s 的子串 s[i,j]
是不是迴文。
需要注意的就是第二個迴圈遍歷的順序如下圖所示(折線表示計算的順序
):