给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
根据回文串的定义可知,单个字符一定是回文串,两个相同的字符一定是回文串,如果在回文串的两端加上相同的字符那么得到的结果必定也是回文串。因此,可以从内往外逐步扩展,因为回文串的两端添加相同的字符后仍然是回文串,因此可以逐步向两端外移,判断得到的新字符串是否仍然是回文串,最后返回具有最大长度的结果。
class Solution:
def longestPalindrome(self, s: str) -> str:
if s == '' or len(s) == 1: return s
def expand(l, r):
# 找出给定字符串中可能的最长字串的长度
while 0 <= l and r < length and s[l] == s[r]:
l -= 1
r += 1
return r - l - 1
length = len(s)
# start和end用于记录当前最长的回文字串的起始和终止索引
start, end = 0, 0
for i in range(length):
# 回文串长度为奇数
l1 = expand(i, i)
# 回文串长度为偶数
l2 = expand(i, i + 1)
maxLen = max(l1, l2)
# 更新当前最长回文子串的索引
if maxLen > (end - start):
start = i - (maxLen - 1) // 2
end = i + maxLen // 2
return s[start: end + 1]
动态规划法: 因为回文串的字串仍然是回文串,因此它满足问题的解可以有子问题的最优解得到,所以可以使用动态规划解决。设置dp数组记录当前索引区间是否是回文串:
dp[i][i] = True
,所有单字符都是回文串- 如果
s[i] == s[i + 1]
,则当前区间字符串可以构成回文串 - 建立动态转移方程
dp[i][j] = (s[i] == s[r]) and dp[i + 1][r- 1] == True
。不断重头遍历更新dp数组
class Solution:
def longestPalindrome(self, s: str) -> str:
if s == '' or len(s) == 1: return s
length = len(s)
# dp[i][j]表示s[i: j]是否是回文串
dp = [[False for i in range(length)] for j in range(length)]
start = 0
maxLen = 1
# 考虑长度为1和2情况的回文串
for i in range(length):
# 所有单字符的情况都是回文串
dp[i][i] = True
# 双字符如果两者相等则是回文串
if i < length - 1 and s[i] == s[i + 1]:
dp[i][i + 1] = True
start = i
maxLen = 2
# 考虑长度超过2的情况
for l in range(3, length + 1):
# 从头开始遍历
for i in range(length - l + 1):
# 可能的回文子串右端索引
r = i + l - 1
# 如果s[i + 1: r - 1]是回文串,那么两端添加相同字符后得到的仍然是回文串
if s[i] == s[r] and dp[i + 1][r - 1]:
dp[i][r] = True
start = i
maxLen = l
return s[start: start + maxLen]