5. 最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
Example
input |
---|
babad |
output |
aba |
input |
---|
cbbd |
output |
bb |
Note
无
思路
经典的动态规划问题
解法一:经典dp O(N2)O(N^2)O(N2)
令dp[i][j]dp[i][j]dp[i][j]表示字符串[位置i......位置j][位置i......位置j][位置i......位置j]是否为回文串,根据回文串的性质
那么有:
{dp[i][j]=True(i==j)dp[i][j]=True(s[i]==s[j]并且i+1==j)dp[i][j]=dp[i+1][j−1](s[i]==s[j])\begin{cases}dp\left[ i\right] \left[ j\right]=True \left(i ==j\right)\\ dp\left[ i\right] \left[ j\right]=True \left( s\left[ i\right] ==s\left[ j\right] 并且 i+1==j\right)\\ dp\left[ i\right] \left[ j\right]=dp\left[ i+1\right] \left[ j-1\right] \left( s\left[ i\right] ==s\left[ j\right] \right)\end{cases}⎩⎪⎨⎪⎧dp[i][j]=True(i==j)dp[i][j]=True(s[i]==s[j]并且i+1==j)dp[i][j]=dp[i+1][j−1](s[i]==s[j])
关键在于状态转移,怎样确定每一个状态,使其没有后效性且对后面求解有利。
可以看到第三个式子中,我们可以先求去dp[i+1][j−1]dp[i+1][j-1]dp[i+1][j−1]的布尔值,使后面的dp[i][j]dp[i][j]dp[i][j]快速判断,所以我们可以选择枚举iii和jjj,那么可以对于一个jjj保持不变,枚举它的iii,那么第三个式子对应的是上个j−1j-1j−1得到的dpdpdp值,完成动态规划
具体代码如下:
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
if n < 2: #小于2直接返回
return s
dp = [[False] * n for _ in range(n)]#创建全为false的二维数组
ml = 1
st = 0
for i in range(n):#首先一个字符肯定是回文串
dp[i][i]=True
for j in range(1,n):
for i in range(0,j):
dp[i][j] = s[i] == s[j] and (i + 1 == j or dp[i+1][j-1]) #简洁代码写法
"""
if s[i] == s[j]: 如果字符两头相同
if i + 1 == j: 如果此时字符串的长度为2
dp[i][j] = True
else: 否则就判断去掉两头之后的内部字符串
dp[i][j] = dp[i+1][j-1]
"""
if dp[i][j] and j-i+1 > ml:#每次记得更新
ml = j-i+1
st = i
return s[st:st+ml]
解法二:中心扩散法 O(N2)O(N^2)O(N2)
这个算是最容易想到的算法,要求回文串嘛,我们就找回文中心,然后判断以此中心能够构成的最长回文串,取最大值即可。关键在于回文串的奇偶长度,需要细心处理即可。复杂度就为O((2∗n−1)∗n)O((2*n-1)*n)O((2∗n−1)∗n),还是O(n2)O(n^2)O(n2),可以接受的。
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
if n < 2:
return s
nn = 2 * n - 1
ml = 1
st = 0
for i in range (0, nn):
l = 1
k = i // 2
j = 0
if i % 2 != 0:
l = 0
while k - l >= 0 and k + l + 1 < n and s[k - l] == s[k + l + 1]:
l += 1
j = k + 1 - l
l *= 2
else:
while k - l >= 0 and k + l < n and s[k - l] == s[k + l]:
l += 1
j = k + 1 - l
l = 2 * l - 1
if l > ml:
st = j
ml = l
return s[st:st + ml]
解法三:Manacher 算法O(N)O(N)O(N)
目前没兴趣看,留着之后二刷的时候填坑吧