LeetCode 原題,這里主要說一下自己的動態規劃解法和思路,希望對大家理解這個有所幫助。
暴力解法為遍歷所有子串,逐個判斷是否是回文字串。
接下來我們來優化暴力解法,暴力解法的問題在于沒有用到回文字串的特性,只是用了定義去檢驗一個字串是不是回文,所以這個題的題眼在于利用回文字串的特性。
如果一個字串是回文字串,那么去掉左右兩邊的字符之后依然是回文。
也可以說是一個回文字串,左右兩邊加上相同的字符,也是回文字串。
使用索引 i 和 j 來表示一個字符串從索引 i 到 j 的子串,則:
dp[i][j]表示索引i到j的子串是否是回文
dp[i][j] = true表示是回文,反之則為false
dp[i][i]只有一個字符,必是回文
關鍵點在于找到關系:dp[i][j] = dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j);
長的子串dp[i][j]依賴于短的子串dp[i + 1][j - 1],所以由短到長依次計算
1、先計算一個字符,全為true
2、再計算兩個字符,如果兩個字符一樣則為true
3、然后計算大于三個字符,直到整個字符串
1、定義二維數組存儲dp的結果值
2、單個字符(起點終點索引相同)全部為true
3、兩個字符如果字符相同為true(注意數組不要越界)
4、依次循環三個字符、四個字符......
5、有起點索引 i,有子串長度 k 則可以得到終點索引 j (同樣注意數組越界問題)
6、比較回文子串長度與保存的result長度
class Solution {
public String longestPalindrome(String s) {
int len = s.length();
boolean[][] dp = new boolean[len][len];//<1>
String result = s.substring(0, 1);
for (int i = 0; i < len; i++) {
dp[i][i] = true;//<2>
}
for (int i = 0; i < len - 1; i++) {
dp[i][i + 1] = s.charAt(i) == s.charAt(i + 1);//<3>
if (dp[i][i + 1]) {
result = s.substring(i, i + 1 + 1);
}
}
//<4>
for (int k = 3; k <= len; k++) {
for (int i = 0; (i + k) <= len; i++) {
int j = i + k - 1;//<5>
dp[i][j] = dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j);
if (dp[i][j] && (j - i + 1) > result.length()) {//<6>
result = s.substring(i, j + 1);
}
}
}
return result;
}
}