给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
示例 3:
输入:s = "a"
输出:"a"
示例 4:
输入:s = "ac"
输出:"a"
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成
官方动态规划:
时间消耗长达7684ms
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]
个人方案,思想:基于单点状态转移,避免不必要的遍历,时间544ms
class Solution:
def longestPalindrome(self, s: str) -> str:
if(s == s[::-1]):return s
dp,dpStr = [],[]
for i in range(len(s)):
dp.append(0)
dpStr.append('')
dp[0],dpStr[0] = 1,s[0]
for i in range(1,len(s)):
# 分为两种方式,第一种为奇数,第二种偶数
p = 0
while(1):
if(i-p<0 or i+p >len(s)-1):break
if(s[i-p] == s[i+p]):
if(2*p+1>dp[i]):
dp[i],dpStr[i] = 2*p+1,s[i-p:i+p+1]
else:break
p += 1
p = 0
while(1):
if(i-p<0 or i+p >len(s)):break
if(s[i-p] == s[i+p-1]):
if(2*p>dp[i]):
dp[i],dpStr[i] = 2*p,s[i-p:i+p]
else:break
p += 1
for i in range(len(dp)):
if(dp[i] == max(dp)):return dpStr[i]
return max(dpStr)
其他方案:最初个人采用的方案,理论上能实现,但是结果时间爆炸
class Solution:
def longestPalindrome(self, s: str) -> str:
if(s == s[::-1]):return s
m = 0
mStr = None
for i in range(1,len(s)):
curr = s[i:]
find = 0
while(1):
find = curr.find(s[i-1],find)
if(find == -1):
break
data = s[i-1:find + i + 1]
if(data != data[::-1]):continue
if(m < len(data)):
m = len(data)
mStr = data
find += 1
return mStr if(mStr != None) else s[0]