该算法的核心思想是使用中心扩展法(Expand Around Center),它通过从字符串的每个字符(或每对相邻字符)作为回文中心开始,向两边扩展来寻找回文子串。具体步骤如下:
1. 整体思路:
-
回文串有两种类型:
-
奇数长度的回文串:例如
"aba"
,它的中心是单个字符。 -
偶数长度的回文串:例如
"abba"
,它的中心是两个相邻字符。
-
奇数长度的回文串:例如
-
对于每个字符(或每对字符),我们尝试将它们作为回文的中心,向两侧扩展,直到不再满足回文条件。我们计算出当前回文的长度,然后与已知最长的回文长度进行比较,更新最长回文子串的起始和结束位置。
2. 详细步骤:
-
遍历整个字符串,假设每个字符或字符对是回文的中心。
-
对于每个字符
i
:- 调用
expandAroundCenter(s, i, i)
来寻找以该字符为中心的奇数长度回文。 - 调用
expandAroundCenter(s, i, i+1)
来寻找以该字符和下一个字符之间的缝隙为中心的偶数长度回文。
- 调用
-
比较两种情况下得到的回文长度,取较大的那个作为当前字符位置的最大回文长度。如果这个长度比已知的最大回文子串长度大,则更新最大回文子串的起始和结束位置。
3. 中心扩展法(expandAroundCenter
):
- 该函数从传入的中心(可能是一个字符,也可能是两个字符)向外扩展,同时检查两边的字符是否相同。如果相同,则继续扩展;如果不同,则停止扩展。
- 返回扩展后的回文长度。
4. 代码运行流程:
- 对于字符串中的每个字符位置,先以它为中心寻找奇数长度的回文,再以它和下一个字符为中心寻找偶数长度的回文。
- 通过比较两者的长度,更新最长的回文子串。
- 最终,返回找到的最长回文子串。
5. 时间复杂度:
该算法的时间复杂度为 O(n^2),其中 n
是字符串的长度。虽然嵌套的循环看似复杂,但实际上每次扩展操作的时间都是线性的。因为每个字符最多被处理两次(一次作为奇数中心,一次作为偶数中心),所以整体的时间复杂度为 O(n^2)。
总结:
- 中心扩展法是解决回文子串问题的一种高效方法,它的核心思想是从每个字符或字符对作为中心,向外扩展寻找最长回文。
- 该方法的时间复杂度为 O(n^2),对于大多数实际问题来说是可接受的。
class Solution {
public String longestPalindrome(String s) {
int start = 0, end = 0;//用于记录最长回文子串的起始和终止下标
for(int i = 0; i < s.length(); ++i) {
int oddPalindromelen = expandAroundCenter(s, i, i);
//这里传入的i+1是作为expandAroundCenter的参数,s字符串并不会访问到,不用担心越界。
int evenPalindromelen = expandAroundCenter(s, i, i + 1);
int maxPalindromeLen = Math.max(evenPalindromelen, oddPalindromelen);
//更新最长回文子串的起始和终止下标
if(maxPalindromeLen >= end - start + 1) { //新回文长度大于或等于当前回文长度时更新最长回文子串的边界
start = i - (maxPalindromeLen - 1) / 2;
end = i + maxPalindromeLen / 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; // 返回的是 right - left - 1,而不是 right - left + 1,
// 原因是当 while 循环结束时,left 和 right 的值已经超出了有效回文串的边界。
}
}