一、题目描述
给你一个字符串 s
,找到 s
中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd" 输出:"bb"
提示:
1 <= s.length <= 1000
s
仅由数字和英文字母组成
二、解题思路
这道题的解题思路是基于“中心扩展”算法,该算法的核心思想是利用回文字符串的特性:一个回文字符串的中心可以是一个字符,也可以是两个相同字符之间的空隙。算法的步骤如下:
- 初始化最长回文子串的长度(maxLen)和起始位置(start)。
- 遍历字符串的每个可能的中心点,包括单个字符(奇数长度的回文)和两个字符之间的空隙(偶数长度的回文)。
- 对于每个中心点,使用辅助函数
expandAroundCenter
来尝试扩展回文。这个函数会从中心点开始,向两边扩展,直到找到不匹配的字符为止。 - 更新最长回文子串的长度和起始位置。如果当前扩展的回文子串长度大于之前记录的最长回文子串长度,就更新这些值。
- 在遍历结束后,使用
substring
方法根据记录的起始位置和长度返回最长回文子串。
三、具体代码
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return "";
}
int n = s.length();
int maxLen = 1;
int start = 0;
int end = 0;
// 遍历所有可能的中心点
for (int i = 0; i < n; i++) {
// 以i为中心,尝试扩展奇数长度的回文
int len1 = expandAroundCenter(s, i, i);
// 以i和i+1为中心,尝试扩展偶数长度的回文
int len2 = expandAroundCenter(s, i, i + 1);
// 更新最大回文长度和起始位置
int len = Math.max(len1, len2);
if (len > maxLen) {
maxLen = len;
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),空间复杂度是O(1)。
1. 时间复杂度
expandAroundCenter
方法在最坏情况下需要遍历整个字符串,时间复杂度为O(n),其中n是字符串的长度。- 主方法
longestPalindrome
中有两个嵌套的循环,外层循环遍历所有可能的中心点(n个),内层循环(expandAroundCenter
)在最坏情况下遍历整个字符串。 - 因此,总的时间复杂度是O(n * n),即O(n^2)。
2. 空间复杂度
- 除了输入的字符串
s
之外,代码中使用了两个整数变量maxLen
、start
和end
来存储最长回文子串的长度和起始位置,以及一个整数变量len
来存储当前回文的长度。 expandAroundCenter
方法中使用了两个整数变量left
和right
来表示当前扩展的回文的边界。- 这些变量都是常数级别的,不随输入字符串长度的增加而增加。
- 因此,空间复杂度是O(1)。
五、总结知识点
-
字符串处理:代码中使用了
String
类的charAt
和substring
方法来处理字符串,这是Java中处理字符串的基本操作。 -
动态规划:虽然这段代码没有直接使用动态规划,但它的思想被隐含在
expandAroundCenter
方法中。这个方法尝试从中心点向两边扩展,直到找到不匹配的字符,这类似于动态规划中的状态转移。 -
循环控制:代码中使用了
for
循环来遍历字符串的所有可能中心点,以及while
循环在expandAroundCenter
方法中实现回文的扩展。 -
条件判断:代码中使用了
if
语句来判断是否找到了更长的回文子串,并更新最长回文子串的长度和起始位置。 -
递归思想:虽然代码没有直接使用递归,但
expandAroundCenter
方法的实现类似于递归过程,它不断地尝试向两边扩展,直到无法继续。 -
边界条件处理:在处理字符串为空或长度为0的情况时,代码正确地返回了空字符串,这是对输入边界条件的有效处理。
-
辅助方法:
expandAroundCenter
是一个辅助方法,用于实现特定的功能(扩展回文),这是面向对象编程中常见的设计模式。 -
数学运算:代码中使用了数学运算(如
len1 + 1
和(len - 1) / 2
)来计算回文子串的长度和起始位置。 -
异常处理:代码在处理可能的
null
输入时,使用了条件判断来避免NullPointerException
。 -
算法效率:代码考虑了算法的时间复杂度,通过只遍历一次字符串来寻找最长回文子串,而不是多次遍历,这提高了算法的效率。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。