返回

LeetCode 解题系列:最长回文子串全方位解法

前端

作为一名刚刚起步的前端开发者,我怀着无比的渴望和敬畏之情踏上了 LeetCode 的解题之旅。在解决最长回文子串问题时,我如饥似渴地钻研了网络上的各种解法,并从中受益匪浅。为了回馈社区,我决定将自己的心得体会整理成文,与大家分享。

问题背景

给定一个字符串 s,找出其中长度最长的回文子串。回文子串是指从左到右和从右到左读起来都相同的子串。例如,在字符串 "babad" 中,最长的回文子串是 "bab"。

解法一:动态规划

动态规划是一种自底向上的解决问题的技术。对于最长回文子串问题,我们可以构建一个二维表格 dp,其中 dp[i][j] 表示字符串 s 从下标 i 到下标 j 的子串是否为回文串。

def longest_palindrome_dp(s):
    n = len(s)
    dp = [[False] * n for _ in range(n)]

    # 基础情况:单个字符和相邻字符
    for i in range(n):
        dp[i][i] = True
    for i in range(n - 1):
        if s[i] == s[i + 1]:
            dp[i][i + 1] = True

    # 对于长度大于 2 的子串
    for l in range(3, n + 1):
        for i in range(n - l + 1):
            j = i + l - 1
            if s[i] == s[j] and dp[i + 1][j - 1]:
                dp[i][j] = True

    max_len = 0
    start = 0
    for i in range(n):
        for j in range(n):
            if dp[i][j] and j - i + 1 > max_len:
                max_len = j - i + 1
                start = i

    return s[start:start + max_len]

解法二:马拉车算法

马拉车算法是一种寻找字符串中所有回文子串的算法。其核心思想是将每个字符作为回文子串的中心,然后向左右两侧扩展,直到找到回文子串的边界。

def longest_palindrome_manacher(s):
    # 预处理字符串,在每个字符之间插入特殊字符 '#'
    s = '#' + '#'.join(s) + '#'

    # 构建马拉车数组
    n = len(s)
    p = [0] * n
    center = right = 0
    max_len = 0

    for i in range(1, n - 1):
        if i < right:
            p[i] = min(right - i, p[2 * center - i])
        while i - p[i] - 1 >= 0 and i + p[i] + 1 < n and s[i - p[i] - 1] == s[i + p[i] + 1]:
            p[i] += 1

        if i + p[i] > right:
            center = i
            right = i + p[i]

        if p[i] > max_len:
            max_len = p[i]
            start = i - max_len

    return s[start:start + max_len].replace('#', '')

解法三:中心扩展法

中心扩展法与马拉车算法类似,都是从每个字符作为回文子串的中心开始扩展。不同之处在于中心扩展法每次只扩展一个单位,直到找到回文子串的边界。

def longest_palindrome_center_expand(s):
    max_len = 0
    start = 0
    for i in range(len(s)):
        left, right = i, i
        # 扩展奇数长度回文子串
        while left >= 0 and right < len(s) and s[left] == s[right]:
            if right - left + 1 > max_len:
                max_len = right - left + 1
                start = left
            left -= 1
            right += 1

        # 扩展偶数长度回文子串
        left, right = i, i + 1
        while left >= 0 and right < len(s) and s[left] == s[right]:
            if right - left + 1 > max_len:
                max_len = right - left + 1
                start = left
            left -= 1
            right += 1

    return s[start:start + max_len]

性能比较

三种解法在不同情况下表现各有优劣。动态规划适用于任意字符串,时间复杂度为 O(n^2)。马拉车算法和中心扩展法更适合寻找最长回文子串,时间复杂度均为 O(n)。

总结

最长回文子串问题是 LeetCode 中经典且重要的题目。通过动态规划、马拉车算法和中心扩展法三种解法的讲解,我们深入剖析了回文子串的本质,掌握了不同的解题思路。希望这篇文章能给您带来启发,助您在 LeetCode 解题之旅中取得进步。