给你一个字符串 s
,找到 s
中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd" 输出:"bb"
提示:
1 <= s.length <= 1000
s
仅由数字和英文字母组成
一开始我直接用的两个for循环就通过了但是时间不太理想
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
result = ''
for i in range(n):
for j in range(i,n):
k = s[i:j+1]
if k == k[::-1]:
if len(k) > len(result):
result = k
return result
对算法进行优化:
第一种方法:中间扩散
- 枚举每个点作为回文串的中心点,左右扩散,如果左边等于右边则继续扩散
- 注意要考虑回文串长度为奇偶的情况
s = "babad"
n = len(s)
res = ""
for i in range(n):
# 回文子串为奇数,左右起始位置在中心点两边
l, r = i - 1, i + 1
while l >= 0 and r < n and s[l] == s[r]:
l, r = l - 1, r + 1
if (r - l - 1 > len(res)): #注意此时的s[r]和s[l]是不相等的所以要减一
res = s[l + 1: r]
# 回文子串为偶数,左右起始位置为中心点及中心点右边
l, r = i, i + 1
while l >= 0 and r < n and s[l] == s[r]:
l, r = l - 1, r + 1
if (r - l - 1 > len(res)):
res = s[l + 1: r]
print(res)
第二种方法:动态规划
思路
状态表示:f[i][j] 区间s[i~j]是否为回文串 True 或者 False,状态表示为数组f[i][j]为True的集合
属性:数组f[i][j]为True的集合中j-i+1的最大值
状态计算
判断区间是否为回文串即s[i]==s[j] and f[i+1][j-1]==True
初始化时需要注意,区间长度为一的切片一定是回文串,另长度为2的区间需要进行特判
区间dp枚举时注意先枚举区间长度
s = "babad"
n = len(s)
# if n < 2:
# print(s) # 长度为1直接返回
start, maxLen = 0, 1 # 维护最长回文串的开始位置以及长度
f = [[False] * n for _ in range(n)]
for i in range(n):
f[i][i] = True # 长度为1的区间为回文串
for length in range(2, n + 1): # 从2开始枚举区间长度
for l in range(n): # 枚举区间左端点
r = l + length - 1
if r >= n:
break # 避免出现右端点越界的情况
if s[l] == s[r]:
if f[l + 1][r - 1] or length == 2: # 长度为2需要特判
f[l][r] = True
if length > maxLen:
start, maxLen = l, length
print(s[start:start + maxLen])