给你一个字符串 s
,找到 s
中最长的 回文子串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd" 输出:"bb"
提示:
1 <= s.length <= 1000
s
仅由数字和英文字母组成
思路一:动态规划dp
使用i,j作为回文串的左右边界,由外向内收束。
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
if n < 2:
return s
max_len = 1
begin = 0
# dp[i][j] 表示 s[i..j] 是否是回文串
dp = [[False] * n for _ in range(n)]
for i in range(n):
dp[i][i] = True
# 递推开始
# 先枚举子串长度
for L in range(2, n + 1):
# 枚举左边界,左边界的上限设置可以宽松一些
for i in range(n):
# 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
j = L + i - 1
# 如果右边界越界,就可以退出当前循环
if j >= n:
break
if s[i] != s[j]:
dp[i][j] = False
else:
if j - i < 3:
dp[i][j] = True
else:
dp[i][j] = dp[i + 1][j - 1]
# 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
if dp[i][j] and j - i + 1 > max_len:
max_len = j - i + 1
begin = i
return s[begin:begin + max_len]
思路二:中心扩散
先确定回文串的中心字符 ,由中心向两侧扩散,记录最长回文串的起始边界和结束边界。
class Solution:
def longestPalindrome(self, s: str) -> str:
def expandAroundCenter(s, left, right):
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
return left + 1, right # 这里 right 已经 +1 了,直接返回
start, max_len = 0, 0
for i in range(len(s)):
for l, r in (expandAroundCenter(s, i, i), expandAroundCenter(s, i, i + 1)):
if r - l > max_len:
start, max_len = l, r - l
return s[start:start + max_len]
思路三:预先处理字符串+Manacher 算法
用于寻找字符串中的最长回文子串。Manacher 算法的核心思想是利用回文的对称性来减少不必要的计算,从而将时间复杂度降低到 O(n) 。
1. 预处理字符串:通过在字符串的每个字符之间插入特殊字符(如 # ),将所有可能的回文子串转换为奇数长度的格式。这样可以统一处理奇数长度和偶数长度的回文子串。
2. 动态规划与对称性:利用已知的回文信息来快速计算新的回文半径,避免重复计算。
3. 线性时间复杂度:通过维护当前已知的最长回文的中心和右边界,确保每个字符最多被处理两次,从而实现线性时间复杂度。
class Solution:
def longestPalindrome(self, s: str) -> str:
# 预处理字符串,插入特殊字符(如#)以处理偶数长度回文
processed_str = '#'.join('^{}$'.format(s))
n = len(processed_str)
p = [0] * n # p[i] 表示以 i 为中心的最长回文半径
center = right = 0 # center 是当前回文的中心,right 是回文的最右边界
for i in range(1, n - 1):
# 利用对称性快速计算 p[i]
if i < right:
p[i] = min(right - i, p[2 * center - i])
# 尝试扩展回文
while processed_str[i + p[i] + 1] == processed_str[i - p[i] - 1]:
p[i] += 1
# 更新最右边界和中心
if i + p[i] > right:
center, right = i, i + p[i]
# 找到最长回文的中心和半径
max_len, center_index = max((p[i], i) for i in range(n))
start = (center_index - max_len) // 2
end = start + max_len
return s[start:end]