最长回文子串
题目要求
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
思路
寻找最长回文子串,也就是求一个字符串中的最优解。谈到最优解,首先应该想到动态规划算法。也就是把一个问题分成若干独立小问题,前一步问题为后一步问题做铺垫,并且将每一步的结果储存起来。这样,这个问题就成为了寻找最短回文子串,并将其一步步扩充为最长回文子串。
-
使用动态规划,用二维数组去存储每一步的结果。
-
将字串倒置,找出倒置子串与源子串重合的部分。
-
判定重合的部分是否为回文串。
反例:
aacbecaa 并不包含回文串,将其倒置之后,aacebcaa, aac和倒置后caa部分相重合,所以必须重新判断它是否为一个回文子串。例子:以 abacd为例,
第一步:
将 cell [i] [j] 行列相等的部分单元格内数字置为1.
第二步:
到了第二个 cell [i] [j]行列相等的时候,查看cell [i-1] [j-1] 内单元格数字是否为 1 ,为1的话进行累加。
第三步:
第三步同上,继续查看cell [i-1] [j-1]单元格,将单元格内的数字累加值 cell [i] [j]。
解释:
累加部分就代表了动态规划中的保存每一步的结果,并供下一步使用,加到最后,我们只需要关注矩阵中的最大值和 列数 J 的值。 J 对应着原字符串中的回文串最后一位的索引,矩阵最大值代表回文串的长度。至此,就可以得到最长的回文串。
代码
public String longestPalindrome(String s) {
//存贮每一步运行结果
int[][] cell = new int[s.length()][s.length()];
int len = 0;
int maxEnd = 0;
String strReverse = new StringBuffer(s).reverse().toString();
for (int i = 0; i < s.length(); i++) {
for (int j = 0; j < strReverse.length(); j++) {
if (strReverse.charAt(i) == s.charAt(j)) {
if (i == 0 || j == 0)
cell[i][j] = 1;
else {
cell[i][j] = cell[i - 1][j - 1] + 1;
}
if (len < cell[i][j] ) {
//效验是否为回文串
if (s.substring(j + 1 - cell[i][j], j + 1).equals(new StringBuffer(s.substring(j + 1 - cell[i][j], j + 1)).reverse().toString())) {
len = cell[i][j];
// J 的下标从零开始
maxEnd = j + 1;
}
}
} else {
cell[i][j] = 0;
}
}
}
return s.substring(maxEnd - len, maxEnd );
}