一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情。
题目描述
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母组成
思路
最长回文子串,这里选用的是一个比较low,但可能好懂一些的思路来做。采用动态规划的思路,就可以解决这个题目。
对于字符里面的某个子串而言,我们先假设它为回文串,它的长度大于2,如果将该子串的首位两个字母都去除之后,它仍然是一个回文串,例如,“saas” ,去除后 “aa" ,"aa"也肯定会为回文字符串,因为去掉的首字母跟尾字母都是”s".
代码
private static String longestPalindrome(String s) {
//获取字符串长度
int len = s.length();
//如果长度小于2,则没有判断的意义。
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;
}
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);
}
public static void main(String[] args) {
String s = "asdsa";
System.out.println(longestPalindrome(s));
String s1 = "asdsaasdsa";
System.out.println(longestPalindrome(s1));
String s2 = "bvcxzbvcxz";
System.out.println(longestPalindrome(s2));
String s3 = "zxcvbbvcxz";
System.out.println(longestPalindrome(s3));
}
运行结果
asdsa
asdsaasdsa
b
zxcvbbvcxz
总结
最长回文字符串这个算法的时间复杂度稍高,,有O(n^2),空间复杂度:O(n^2),但是思路其实是很容易就能理解的,通过仔细思考,慢慢来一步步的去理顺逻辑,就能很快速的完成这个题目等后续还得再把其他好一点的解法再补充进来。慢慢来