给你一个字符串 s
,找到 s
中最长的回文子串。
思路:分成两步:1.判断一个字符串是否是回文序列;2.寻找首尾相同的子串
自己编写的代码如下:
class Solution {
public String longestPalindrome(String s) {
String result = s.substring(0, 1);
if (isTrue(s)){
result = s;
}else{
for (int i = 0; i < s.length(); i++) {
for (int j = i+1; j < s.length(); j++) {
if (s.charAt(i) == s.charAt(j) && isTrue(s.substring(i, j+1))){
if (s.substring(i, j+1).length() > result.length()){
result = s.substring(i, j+1);
}
}
}
}
}
return result;
}
// 判断一个字符串是否是一个回文序列
public boolean isTrue(String s){
for (int i = 0; i < s.length()/2; i++) {
if (s.charAt(i) != s.charAt(s.length()-i-1)){
return false;
}
}
return true;
}
}
问题:
本方法属于暴力破解,时间复杂度为
改进:采用动态规划,对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。
按照子串长度从小到大的顺序,依次给dp数组赋值,如果是回文序列,则为true
当判断长度为i的子串是否是回文序列时,只需要看长度为i-2的子串是否是回文序列且头尾是否相同即可.
代码如下:
public class Solution {
public String longestPalindrome(String s) {
int len = s.length();
if (len < 2) {
return s;
}
int maxLen = 1;
int begin = 0;
// dp[i][j] 表示 s[i..j] 是否是回文串
boolean[][] dp = new boolean[len][len];
// 初始化:所有长度为 1 的子串都是回文串
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
char[] charArray = s.toCharArray();
// 递推开始
// 先枚举子串长度
for (int L = 2; L <= len; L++) {
// 枚举左边界,左边界的上限设置可以宽松一些
for (int i = 0; i < len; i++) {
// 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
int j = L + i - 1;
// 如果右边界越界,就可以退出当前循环
if (j >= len) {
break;
}
//先看头尾是否相同,若相同则把头尾去掉后,根据dp数组的取值,判断是否是回文序列
if (charArray[i] != charArray[j]) {
dp[i][j] = false;
} else {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
// 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substring(begin, begin + maxLen);
}
}