给你一个字符串 s
,找到 s
中最长的回文子串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd" 输出:"bb"
示例 3:
输入:s = "a" 输出:"a"
示例 4:
输入:s = "ac" 输出:"a"
示例代码1:
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]
示例代码2:【此方法的执行时间效率要高于方法一】
class Solution:
def expendAroundCenter(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.expendAroundCenter(s, i, i)
left2, right2 = self.expendAroundCenter(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]
示例代码3:【中心扩散】
class Solution:
def longestPalindrome(self, s: str) -> str:
maxl,max_len,n = 0,0,len(s)
for i in range(2*n-1):
l,r = i//2,i//2+i%2
while l>=0 and r < n and s[l]==s[r]:
if r-l+1>max_len: maxl,max_len = l,r-l+1
l-=1
r+=1
return s[maxl:maxl+max_len]
解题思路:
- 回文串:1个中心 + 左右等距扩散
- 回文中心:奇数长回文串1个中心字符,偶数长2个中心字符
- 中心数目:对于n长原始字符串s,一共有2n-1个回文中心
遍历2n-1个回文中心,确定中心后,check能否左右扩散
左右扩散:l>=0 and r<n and s[l]==s[r]
左右指针:l=i//2,r=i//2+i%2
扩散过程中通过maxl,max_len确定最长回文串的左端点和长度
- 结果返回:s[maxl:maxl+max_len]
- 时间:o(n^2)
- 空间:o(1)