题目
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例 2:
输入:s = “cbbd”
输出:“bb”
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母组成
java
要找到字符串中最长的回文子串,可以使用动态规划或中心扩展的方法。下面是一个使用中心扩展的Java代码示例:
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) {
return "";
}
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);
}
private int expandAroundCenter(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--;
right++;
}
return right - left - 1;
}
}
这个代码使用了中心扩展的思想,遍历字符串中的每个字符,以每个字符为中心向两边扩展,找到以该字符为中心的最长回文子串。然后,比较每个字符为中心的回文子串,找到最长的那个。
最终返回最长回文子串。这个算法的时间复杂度为O(n^2),其中n是字符串的长度。
java 代码2
Manacher算法是一种用于查找最长回文子串的高效算法,其核心思想是利用已知的回文子串信息来加速查找。下面是对Manacher算法的具体题解:
预处理:Manacher算法的第一步是将原始字符串预处理,将问题简化为处理奇数长度的回文串。这是通过在每个字符之间插入特殊字符(通常是“#”)来实现的。
初始化:创建一个新的字符串,用于预处理后的字符串。同时,创建一个数组p
,用于存储以每个字符为中心的回文子串的半径长度。
遍历:从预处理字符串的第一个字符开始,依次处理每个字符。在遍历的过程中,维护两个变量center
和right
,它们表示当前找到的最长回文子串的中心和右边界。
中心扩展:以每个字符为中心,尝试向左右两侧扩展,以查找回文子串。在扩展的过程中,使用mirror
变量来查找对称位置的字符,从而可以更快地计算回文子串的半径。
更新center
和right
:如果当前回文子串的右边界超过了right
,则更新center
和right
。这样,算法可以在查找下一个回文子串时利用已知信息。
寻找最长回文子串:在遍历的同时,记录最长回文子串的半径长度和中心位置。
最终结果:根据最长回文子串的信息,计算原始字符串中的起始位置和结束位置,从而得到最长回文子串。
以下是Manacher算法的Java代码
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) {
return "";
}
// 预处理字符串,插入特殊字符,使字符串的长度为奇数
String transformedString = preProcess(s);
int n = transformedString.length();
int[] p = new int[n]; // 用于存储回文子串的半径长度
int center = 0, right = 0; // 当前找到的最长回文子串的中心和右边界
for (int i = 1; i < n - 1; i++) {
int mirror = 2 * center - i; // 查找对称位置的字符
if (right > i) {
p[i] = Math.min(right - i, p[mirror]); // 初始值是已知的回文子串信息
}
// 尝试扩展回文子串
while (transformedString.charAt(i + p[i] + 1) == transformedString.charAt(i - p[i] - 1)) {
p[i]++;
}
// 如果回文子串的右边界扩展超过了 right,更新 center 和 right
if (i + p[i] > right) {
center = i;
right = i + p[i];
}
}
int maxLen = 0;
int centerIndex = 0;
// 寻找最长回文子串的半径长度和中心位置
for (int i = 1; i < n - 1; i++) {
if (p[i] > maxLen) {
maxLen = p[i];
centerIndex = i;
}
}
// 计算原始字符串中的起始位置和结束位置
int start = (centerIndex - maxLen) / 2;
int end = start + maxLen;
return s.substring(start, end);
}
// 预处理函数,将原始字符串转换为用于Manacher算法的格式
private String preProcess(String s) {
int n = s.length();
if (n == 0) {
return "^$";
}
StringBuilder sb = new StringBuilder("^");
for (int i = 0; i < n; i++) {
sb.append("#").append(s.charAt(i));
}
sb.append("#$");
return sb.toString();
}
}