📅  最后修改于: 2023-12-03 15:40:17.048000             🧑  作者: Mango
回文字符串就是正着和倒着读都一样的字符串。比如:"level"、"racecar"、"madam"都是回文字符串。而"hello"、"world"则不是。
给定一个字符串s,找到s中最长的回文子串。你可以假设s的最大长度为1000。
最朴素的思路当然是从字符串的第一个字符开始,枚举所有子串,对于每个子串都判断一下是不是回文串,最后找到最长的那个回文串。这样的时间复杂度是O(n^3),由于n=1000,所以这个算法会非常慢。
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
ans = ''
for i in range(n):
for j in range(i, n):
if s[i:j+1] == s[i:j+1][::-1]:
if len(s[i:j+1]) > len(ans):
ans = s[i:j+1]
return ans
可以思考一下回文串的性质:若s[l:r+1]是一个回文串,那么s[l+1:r]也必定是回文串。基于这个性质,我们可以枚举中心位置i,向两边拓展,直到找到最长的回文串。
但是需要特别处理两种情况:回文串长度是奇数的情况,和回文串长度是偶数的情况。
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
start, end = 0, 0
for i in range(n):
# 回文串长度为奇数
left, right = i, i
while left >= 0 and right < n and s[left] == s[right]:
left -= 1
right += 1
if right - left - 1 > end - start:
start = left + 1
end = right
# 回文串长度为偶数
left, right = i, i + 1
while left >= 0 and right < n and s[left] == s[right]:
left -= 1
right += 1
if right - left - 1 > end - start:
start = left + 1
end = right
return s[start:end]
如果一个字符串是回文串,那么去掉两端的字符后剩下的字符串也是回文串。基于这个性质,我们可以设计一个动态规划算法。
定义状态f(i, j)表示s[i:j+1]是否是回文串,如果是,f(i, j)为True,否则为False。
状态转移方程:
边界条件:
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
f = [[False] * n for _ in range(n)]
start, end = 0, 0
for i in range(n):
for j in range(i+1):
if s[i] == s[j] and (i - j < 2 or f[j+1][i-1]):
f[j][i] = True
if i - j + 1 > end - start:
start = j
end = i
return s[start:end+1]
这个算法的时间复杂度是O(n^2),比中心拓展算法优秀一些,但空间复杂度是O(n^2),需要开辟一个二维数组。但是可以通过滚动数组将空间复杂度降到O(n)。