本文我们来寻找隐藏在字符串中的小妖精——最长回文子串。
大家好!今天我们来聊一聊一个有趣的问题:如何在一个字符串中找到最长的回文子串。这道题是LeetCode上的第5题,乍一看,好像是在跟我们玩捉迷藏。回文子串是什么?它其实就是那些可以正着读倒着读都一样的字符串,比如“madam”或者“racecar”。接下来,我们要开启一段充满魔法和智慧的旅程,揭开这个隐藏在字符串中的小妖精——最长回文子串。
在找到最长回文子串之前,我们需要一点策略。我们有几种方法来解决这个问题,像是暴力破解法、中心扩展法和动态规划法。今天我们重点讲解的是中心扩展法,它就像是我们站在一个舞台中央,向四周发出魔法光波,寻找最长的回文。
中心扩展法的基本思路是这样的:每个字符(甚至每个字符之间的空隙)都可能是一个回文中心。我们从每个中心开始,向两边扩展,看看能找到多长的回文子串。最后,我们选取最长的那个。
初始化变量
start
和 end
用来记录最长回文子串的起始和结束位置。扩展回文
返回结果
public class LongestPalindrome {
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;
}
}
使用Mermaid语法来展示这个过程,如下图所示:
int start = 0, end = 0;
这里,我们初始化了两个变量start
和end
,用来记录最长回文子串的起始和结束位置。
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;
}
}
我们遍历整个字符串,假设每个字符和每个字符之间的空隙都是一个潜在的回文中心。
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;
}
在expandAroundCenter
方法中,我们从中心开始,向两边扩展,直到无法扩展为止。返回扩展后的回文长度。
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
如果找到的回文长度比当前记录的最长回文更长,就更新起始和结束位置。
return s.substring(start, end + 1);
最后,根据记录的起始和结束位置,截取并返回最长的回文子串。
让我们通过字符串 “babad” 来解释这个过程:
初始状态
start = 0
, end = 0
遍历字符串并扩展回文
中心在 ‘b’ (i = 0)
start = 0
, end = 0
(最长回文 “b”)中心在 ‘a’ (i = 1)
start = 0
, end = 2
(最长回文 “bab”)中心在 ‘b’ (i = 2)
start = 1
, end = 3
(最长回文 “aba”)中心在 ‘a’ (i = 3)
start = 1
, end = 3
(最长回文 “aba”)中心在 ‘d’ (i = 4)
start = 1
, end = 3
(最长回文 “aba”)返回结果
s.substring(start, end + 1) = "aba"
让我们通过字符串 “cbbd” 来解释这个过程:
初始状态
start = 0
, end = 0
遍历字符串并扩展回文
中心在 ‘c’ (i = 0)
start = 0
, end = 0
(最长回文 “c”)中心在 ‘b’ (i = 1)
start = 1
, end = 2
(最长回文 “bb”)中心在 ‘b’ (i = 2)
start = 1
, end = 2
(最长回文 “bb”)中心在 ‘d’ (i = 3)
start = 1
, end = 2
(最长回文 “bb”)返回结果
s.substring(start, end + 1) = "bb"
让我们通过字符串 “a” 来解释这个过程:
初始状态
start = 0
, end = 0
遍历字符串并扩展回文
start = 0
, end = 0
(最长回文 “a”)返回结果
s.substring(start, end + 1) = "a"
让我们通过字符串 “ac” 来解释这个过程:
初始状态
start = 0
, end = 0
遍历字符串并扩展回文
中心在 ‘a’ (i = 0)
start = 0
, end = 0
(最长回文 “a”)中心在 ‘c’ (i = 1)
start = 0
, end = 0
(最长回文 “a”)返回结果
s.substring(start, end + 1) = "a"
通过这几个例子,我们展示了如何使用中心扩展法找到字符串中的最长回文子串。这个方法的核心在于从每个可能的中心开始扩展,寻找最长的回文子串。尽管时间复杂度是O(n^2),但对于大多数实际情况已经足够高效。
通过这些例子,我们可以看到,无论是字符串中有多个回文子串还是只有一个字符的字符串,中心扩展法都能够有效地找到最长的回文子串。希望这个幽默风趣的解题过程能帮助你更好地理解中心扩展法。
如果本文对您有所帮助的话,请收藏文章、关注作者、订阅专栏,感激不尽。