LC5-最长回文子串(Python 三解法,性能逐步提升)

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母组成

思路一:动态规划dp

使用i,j作为回文串的左右边界,由外向内收束。

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]

思路二:中心扩散

先确定回文串的中心字符 ,由中心向两侧扩散,记录最长回文串的起始边界和结束边界。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        def expandAroundCenter(s, left, right):
            while left >= 0 and right < len(s) and s[left] == s[right]:
                left -= 1
                right += 1
            return left + 1, right  # 这里 right 已经 +1 了,直接返回

        start, max_len = 0, 0
        for i in range(len(s)):
            for l, r in (expandAroundCenter(s, i, i), expandAroundCenter(s, i, i + 1)):
                if r - l > max_len:
                    start, max_len = l, r - l

        return s[start:start + max_len]

 思路三:预先处理字符串+Manacher 算法

用于寻找字符串中的最长回文子串。Manacher 算法的核心思想是利用回文的对称性来减少不必要的计算,从而将时间复杂度降低到 O(n) 。

1. 预处理字符串:通过在字符串的每个字符之间插入特殊字符(如   #  ),将所有可能的回文子串转换为奇数长度的格式。这样可以统一处理奇数长度和偶数长度的回文子串。

2. 动态规划与对称性:利用已知的回文信息来快速计算新的回文半径,避免重复计算。

3. 线性时间复杂度:通过维护当前已知的最长回文的中心和右边界,确保每个字符最多被处理两次,从而实现线性时间复杂度。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        # 预处理字符串,插入特殊字符(如#)以处理偶数长度回文
        processed_str = '#'.join('^{}$'.format(s))
        n = len(processed_str)
        p = [0] * n  # p[i] 表示以 i 为中心的最长回文半径
        center = right = 0  # center 是当前回文的中心,right 是回文的最右边界

        for i in range(1, n - 1):
            # 利用对称性快速计算 p[i]
            if i < right:
                p[i] = min(right - i, p[2 * center - i])

            # 尝试扩展回文
            while processed_str[i + p[i] + 1] == processed_str[i - p[i] - 1]:
                p[i] += 1

            # 更新最右边界和中心
            if i + p[i] > right:
                center, right = i, i + p[i]

        # 找到最长回文的中心和半径
        max_len, center_index = max((p[i], i) for i in range(n))
        start = (center_index - max_len) // 2
        end = start + max_len

        return s[start:end]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值