题目
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:输入: "cbbd"
输出: "bb"来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
动态规划
这个题或许是因为之前做过,一开始直接想到了是一个动态规划的题目。状态转移方程比较好得到,因为规律还是比较明显的。
s[i][j]代表i到j的子串,如果ci = cj且s[i+1][j-1]是回文(i+1 < j-1),那么s[i][j]也一定是回文。对于i==j的一定是回文,i=j-1的,只需要判断二者的字符是否相同即可。
代码如下:
class Solution {
public String longestPalindrome(String s) {
if (s.length() <= 1) return s;
boolean [][]isPalindrome = new boolean[s.length()][s.length()];
for (int i = 0; i < s.length(); i++) {
isPalindrome[i][i] = true;
}
String result = s.substring(0, 1);
int maxLength = 1;
for (int width = 2; width <= s.length(); width++) {
for (int i = 0; i < s.length() - width; i++) {
boolean currentIsPal = (width == 2 || isPalindrome[i + 1][i + width - 2])
&& s.charAt(i) == s.charAt(i + width - 1);
if (currentIsPal) {
isPalindrome[i][i + width - 1] = true;
if (width > maxLength) {
maxLength = width;
result = s.substring(i, i + width);
}
}
}
}
return result;
}
}
时间复杂度:
空间复杂度:
中心扩展
这个题还有一个巧妙的方法,因为最终的回文子串一定是有中心的。而且做长的回文子串也是从短的子串扩展判断来的,所以可以考虑从中心扩展去找最长的回文子串。而且这样的中心点个数是确定的,n为字符串s的长度,中心点个数为2n-1个。
每遍历到一个字符,可以以其为中心点扩散,也可以以其与右侧字符的中间位置作为中心点进行扩散。
代码如下:
class Solution {
public String longestPalindrome(String s) {
if (s.length() <= 1) return s;
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expandAroundCenter(s, i, i);
int len2 = expandAroundCenter(s, i, i + 1);
int len = Math.max(len1, len2);
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substring(start, end + 1);
}
public int expandAroundCenter(String s, int left, int right) {
int L = left, R = right;
while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
L--;
R++;
}
return R - L - 1;
}
}
时间复杂度:
空间复杂度O(1)
暴力法
暴力法还是要说一下的,因为这是解题的第一方法。只有解决题目,才能考虑优化。
暴力法比较简单,就去判断所有子串是不是回文即可。
所有子串的可能性有种,其实精确的说是种可能性(start为0有n种,start为1有n-1种……)。
然后每个子串判断是不是回文,时间复杂度为O(n),从两边往中间遍历比对即可。
manacher算法
这个暂时不看了
耗时:
番茄钟采用正向计时,耗时70分钟。