参考链接:官方最长回文子串
最长回文子串:动态规划——状态转移方程
方法一:动态规划
class Solution:
def longestPalindrome(self, s: str) -> str:
lenn = len(s)
if lenn == 1: # 当长度为1,本身就是最长的回文子串
return s
# 设置初始状态
dp = [[False] * lenn for _ in range(lenn)]
for i in range(lenn):
dp[i][i] = True # 1^ 一个字符一定回文
# 初始答案: 至少《第一个字符》一定构成回文子串
max_len = 1
start = 0
for j in range(1, lenn):
for i in range(j):
# 边界情况
if j - i <= 2 and s[i] == s[j]: # 2^&3^两个相同字符、三个字符的两端相同 一定是回文
dp[i][j] = True
new_len = j - i + 1
# 状态转移:递推公式
else:
if s[i] == s[j] and dp[i+1][j-1]: # 前一列的状态已经更新完成
dp[i][j] = True
new_len = j - i + 1
# 有新的回文子串时,更新为最长
if dp[i][j]:
if new_len > max_len:
max_len = new_len
start = i
return s[start: start + max_len]
方法二:中心拓展
感觉这个比较容易理清思路,主要就是分两种中心:奇、偶数个,然后从左到右遍历一边。
- 时间复杂度:O(n^2 ),其中 n 是字符串的长度。长度为 1 和 2 的回文中心分别有 n 和 n-1 个,每个回文中心最多会向外扩展 O(n)次。
- 空间复杂度:O(1)O(1)
与动态规划相比缩减了空间复杂度。
class Solution:
def expandAroundCenter(self, s, left, right):
while left >= 0 and right < len(s) and s[left] == s[right]: # 向两边拓展,找最长的回文边界
left -= 1
right += 1
return left + 1, right - 1
def longestPalindrome(self, s: str) -> str:
start, end = 0, 0
for i in range(len(s)):
left1, right1 = self.expandAroundCenter(s, i, i) # 奇数
left2, right2 = self.expandAroundCenter(s, i, i + 1) # 偶数
# 更新最长回文子串
if right1 - left1 > end - start:
start, end = left1, right1
if right2 - left2 > end - start:
start, end = left2, right2
return s[start: end + 1]