最长回文子串

5. 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。

 

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

示例 3:

输入:s = "a"
输出:"a"

示例 4:

输入:s = "ac"
输出:"a"

方法一、刚拿到题,如果要在短时间内快速AC,可以暴力枚举,根据回文子串的定义,枚举所有长度大于等于 2 的子串,依次判断它们是否是回文。代码如下

class Solution:
  # 暴力匹配(超时)
  def longestPalindrome(self, s):
    # 特判
    size = len(s)
    if size < 2:
      return s

    max_len = 1
    res = s[0]

  # 枚举所有长度大于等于 2 的子串
    for i in range(size - 1):
      for j in range(i + 1, size):
        if j - i + 1 > max_len and self.__valid(s, i, j):
          max_len = j - i + 1
          res = s[i:j + 1]
    return res

  def __valid(self, s, left, right):
  # 验证子串 s[left, right] 是否为回文串
    while left < right:
    if s[left] != s[right]:
    return False
    left += 1
    right -= 1
   return True

如果题目限制了运行时间,暴力枚举的方法显然会超时。
方法二、动态规划

对于一个子串而言,如果它是回文串,并且长度大于 22,那么将它首尾的两个字母去除之后,它仍然是个回文串。根据这样的思路,我们就可以用动态规划的方法解决本题。我们用 P(i,j)表示字符串 s的第 i到 j 个字母组成的串(下文表示成 s[i:j])是否为回文串。也就是说,只有 s[i+1:j-1]是回文串,并且 s 的第 ii和 j个字母相同时,s[i:j]才会是回文串。上文的所有讨论是建立在子串长度大于 2 的前提之上的,我们还需要考虑动态规划中的边界条件,即子串的长度为 1或 2。对于长度为 11的子串,它显然是个回文串;对于长度为 2的子串,只要它的两个字母相同,它就是一个回文串。因此我们就可以写出动态规划的边界条件。根据这个思路,我们就可以完成动态规划了。代码如下

class Solution:
  def longestPalindrome(self, s: str) -> str:
    n = len(s)
    dp = [[False] * n for _ in range(n)]
    ans = ""
    # 枚举子串的长度 l+1
    for l in range(n):
    # 枚举子串的起始位置 i,这样可以通过 j=i+l 得到子串的结束位置
    for i in range(n):
      j = i + l
      if j >= len(s):
        break
      if l == 0:
        dp[i][j] = True
      elif l == 1:
        dp[i][j] = (s[i] == s[j])
      else:
        dp[i][j] = (dp[i + 1][j - 1] and s[i] == s[j])
      if dp[i][j] and l + 1 > len(ans):
        ans = s[i:j+1]
  return ans

posted @ 2021-03-09 10:30  superjj123  阅读(60)  评论(0)    收藏  举报