返回

用LeetCode-409:寻找最长回文串,提升你的算法技巧

前端

回文探秘:LeetCode-409 算法详解

动态规划:通往回文之巅的阶梯

在算法竞技场中,LeetCode-409 挑战我们寻找给定字母序列中最长的回文串。回文串是一种正读反读都相同的字符串,如 "racecar" 或 "level"。

破解这一难题的利器便是动态规划算法。它将问题分解成一系列子问题,逐步求解,最终汇聚成全局最优解。

假设字符串为 s,长度为 n。我们创建一张二维表 dp,其中 dp[i][j] 表示子字符串 s[i:j+1] 是否为回文串。

子问题的定义:

  • 当 i=j 时,dp[i][j] = True,因为任何单个字符都是回文串。
  • 当 j-i=1 时,dp[i][j] = (s[i]==s[j]),即相邻字符相同。
  • 当 j-i>1 时,dp[i][j] = (s[i]==s[j]) && dp[i+1][j-1],即相邻字符相同且子串 s[i+1:j] 为回文串。

递推公式:

dp[i][j] =
    if i==j:
        True
    elif j-i==1:
        s[i]==s[j]
    else:
        s[i]==s[j] && dp[i+1][j-1]

回溯路径:

求得 dp 表后,我们可以通过回溯,找到最长回文串的构成过程。从 dp[0][n-1] 开始,若 dp[i][j]=True,则将 s[i] 和 s[j] 加入结果串,并继续回溯 dp[i+1][j-1]。

代码实现:

def longest_palindrome(s):
    n = len(s)
    dp = [[False] * n for _ in range(n)]
    max_len = 0
    start = 0

    # 填充dp表
    for i in range(n):
        dp[i][i] = True
    for i in range(n-1):
        dp[i][i+1] = s[i] == s[i+1]

    # 递推求解
    for k in range(2, n):
        for i in range(n-k):
            j = i + k
            dp[i][j] = (s[i] == s[j]) and dp[i+1][j-1]

            # 更新最长回文串
            if dp[i][j] and k > max_len:
                max_len = k
                start = i

    # 回溯构成过程
    result = ""
    i, j = start, start + max_len - 1
    while i <= j:
        result += s[i]
        i += 1
        j -= 1

    return result

进阶拓展:算法之美

掌握了寻找最长回文串的算法后,不妨更进一步,探索它的变种问题:

  • 最长回文子序列: 寻找字符串中最长的回文子序列,而不必相邻。
  • 最长回文子串变位词: 在给定字符串中寻找任意变位词构成的最长回文子串。

算法世界无穷无尽,让我们乘风破浪,勇往直前,不断提升我们的算法思维和编程技巧!

常见问题解答

  1. 什么是回文串?

    • 正读反读都相同的字符串,如 "racecar" 或 "level"。
  2. 动态规划算法如何破解回文串问题?

    • 分解问题为子问题,逐步求解,最终汇聚成全局最优解。
  3. 为什么 dp[i][j] = dp[i+1][j-1]?

    • 只有相邻字符相同时,且子串 s[i+1:j] 为回文串时,dp[i][j] 才为回文串。
  4. 如何回溯最长回文串的构成过程?

    • 从 dp[0][n-1] 开始,若 dp[i][j]=True,则将 s[i] 和 s[j] 加入结果串,并继续回溯 dp[i+1][j-1]。
  5. 除了最长回文子串外,还有哪些回文串变种问题?

    • 最长回文子序列、最长回文子串变位词等。