5. 最长回文子串
基础学自九章算法
1.结果
动态规划 执行结果:
执行用时:70 ms, 在所有 Java 提交中击败了51.78%的用户
内存消耗:44.4 MB, 在所有 Java 提交中击败了27.48%的用户
通过测试用例:140 / 140
2.时间花费
一天
3.思路
一般方法西路:
// 直接循环,两边扩展,记录最长的
// 第一遍,遍历每个字符
// 内部循环,两边扩展,两端不等就返回,为当前最长回文串
// ABA格式
// ABBA格式
动态规划思路:
/**
* 使用动态规划
* step1,确定状态,问题分割:
* 当前子串 + 两边相同的字符
* s[i:j] = s[i+1:j-1] + s[i]==s[j]
* 因此需要二维数组来保存状态结果,构建二维数组 is_palindromic[l][l]
* step2, 转移方程
* is_palindromic[i:j] = is_palindromic[i+1:j-1] && s[i]==s[j]
* step3,初始条件和边界
* step3.1,初始条件(初始化)
* 因为,[i+1:j-1],所以状态转移方程至少是得2个字符才可以+1-1
* 因此,要额外考虑,空字符、一个字符,即:
* if s==“”, return ""
* s[i][i] = ture
*
* is_palindromic[i][i+1] 或者,
* is_palindromic[i][i-1],理解为空
* step3.2,边界
* i,j的边界
* i [0,l-1]
* j [i, l-1]
*
* step4 计算顺序(看转移方程)
* i,j 由 i+1,j-1的来,
* 所以 i 从大到小
* j 从小到大
* final 区间型,使用 start 和 length 记录结果
*
*/
4.code
class Solution {
public String longestPalindrome(String s) {
return palindromic( s);
}
// 直接循环,两边扩展,记录最长的
// 第一遍,遍历每个字符
// 内部循环,两边扩展,两端不等就返回,为当前最长回文串
public static String m1(String s){
String re = "";
// ABA格式
for (int i = 0; i < s.length(); i++){
String reTem = "" + s.charAt(i);
for(int j = 1; j <= i && (i+j) < s.length(); j++){
char pre = s.charAt(i-j);
char tail = s.charAt(i+j);
if(pre==tail){
reTem = pre+reTem+tail;
}else{
break;
}
}
if (re.length() < reTem.length()){
re = reTem;
}
}
// ABBA格式
for (int i = 0; i < s.length()-1; i++){
char pre = s.charAt(i);
char tail = s.charAt(i+1);
if(pre==tail){
String reTem = "" + pre + tail;
for(int j = 1; j <= i && (i+1+j) < s.length(); j++){
pre = s.charAt(i-j);
tail = s.charAt(i+1+j);
if(pre==tail){
reTem = pre+reTem+tail;
}else{
break;
}
}
if (re.length() < reTem.length()){
re = reTem;
}
}
}
return re;
}
public static String palindromic(String s) {
/**
* 使用动态规划
* step1,确定状态,问题分割:
* 当前子串 + 两边相同的字符
* s[i:j] = s[i+1:j-1] + s[i]==s[j]
* 因此需要二维数组来保存状态结果,构建二维数组 is_palindromic[l][l]
* step2, 转移方程
* is_palindromic[i:j] = is_palindromic[i+1:j-1] && s[i]==s[j]
* step3,初始条件和边界
* step3.1,初始条件(初始化)
* 因为,[i+1:j-1],所以状态转移方程至少是得2个字符才可以+1-1
* 因此,要额外考虑,空字符、一个字符,即:
* if s==“”, return ""
* s[i][i] = ture
*
* is_palindromic[i][i+1] 或者,
* is_palindromic[i][i-1],理解为空
* step3.2,边界
* i,j的边界
* i [0,l-1]
* j [i, l-1]
*
* step4 计算顺序(看转移方程)
* i,j 由 i+1,j-1的来,
* 所以 i 从大到小
* j 从小到大
* final 区间型,使用 start 和 length 记录结果
*
*/
if (s == null || "".equals(s)) {
return "";
}
int n = s.length();
boolean re[][] = new boolean[n][n];
int start = 0, length = 1;
// 初始化一个字符的
for (int i = 0; i < n; i++) {
re[i][i] = true;
}
// 初始化两个字符的,这里要考虑计算顺序
for (int i = 0; i < n - 1; i++) {
if (s.charAt(i) == s.charAt(i + 1)) {
re[i][i + 1] = true;
start = i;
length = 2;
}
}
// 一般情况,转移方程,一定要注意推理顺序
for (int i = n - 3; i >= 0; i--) { // 最多到倒数第三个元素
for (int j = i + 2; j < n; j++) {
if (re[i + 1][j - 1] && s.charAt(i) == s.charAt(j)) {
re[i][j] = true;
if (j - i + 1 > length) {
start = i;
length = j - i + 1;
}
}
// System.out.println("(" + i + ", " + j + ") " + re[i][j]);
}
}
return s.substring(start, start + length);
}
}