返回

力扣:动态规划之最长回文子序列

闲谈

动态规划的登堂入室

动态规划,一个听起来很抽象的名词,却在算法和程序设计领域有着举足轻重的地位。动态规划是一种将复杂问题分解为一系列小问题的算法策略,通过求解这些小问题,逐步推导出最终的解决方案。

动态规划的本质是利用子问题的最优解来构造整个问题的最优解。也就是说,如果我们能够找到问题中的子问题,并且这些子问题的最优解能够帮助我们找到整个问题的最优解,那么我们就可以通过动态规划来解决这个问题。

动态规划解决最长回文子序列问题

最长回文子序列问题是一个经典的动态规划问题。给定一个字符串,我们需要找到这个字符串中最长的回文子序列。回文子序列是指一个字符串的子序列,当我们从左到右或从右到左读这个子序列时,它都是一样的。

例如,字符串 "abba" 的最长回文子序列是 "abba" 本身,因为 "abba" 从左到右或从右到左读都是一样的。

动态规划算法步骤

  1. 定义子问题: 对于一个长度为 n 的字符串 s,我们定义子问题 dp[i][j] 为从 s[i]s[j] 的最长回文子序列的长度。其中,0 ≤ i ≤ j ≤ n-1

  2. 初始化子问题: 对于所有 ij,如果 i > j,那么 dp[i][j]0。如果 i = j,那么 dp[i][j]1

  3. 递推公式: 对于所有 ij,如果 i < j,那么 dp[i][j] 可以由以下公式计算:

    • 如果 s[i] = s[j],那么 dp[i][j] = dp[i+1][j-1] + 2
    • 如果 s[i] ≠ s[j],那么 dp[i][j] = max(dp[i+1][j], dp[i][j-1])
  4. 计算最终解: 最长回文子序列的长度为 dp[0][n-1]

代码实现

def longest_palindrome_subsequence(s):
    """
    Returns the longest palindrome subsequence of the given string.

    Args:
        s (str): The string to find the longest palindrome subsequence of.

    Returns:
        str: The longest palindrome subsequence of the given string.
    """

    # Create a 2D array to store the lengths of the longest palindrome subsequences
    # of all substrings of the given string.
    dp = [[0 for _ in range(len(s))] for _ in range(len(s))]

    # Initialize the diagonal elements of the array to 1, since a single character
    # is always a palindrome subsequence of itself.
    for i in range(len(s)):
        dp[i][i] = 1

    # Fill the rest of the array using the遞推公式.
    for i in range(len(s)-1, -1, -1):
        for j in range(i+1, len(s)):
            if s[i] == s[j]:
                dp[i][j] = dp[i+1][j-1] + 2
            else:
                dp[i][j] = max(dp[i+1][j], dp[i][j-1])

    # Find the longest palindrome subsequence by finding the maximum value in the
    # last row of the array.
    max_length = 0
    for i in range(len(s)):
        if dp[i][len(s)-1] > max_length:
            max_length = dp[i][len(s)-1]

    # Construct the longest palindrome subsequence by backtracking through the array.
    longest_palindrome_subsequence = ""
    i = 0
    j = len(s) - 1
    while i <= j:
        if s[i] == s[j]:
            longest_palindrome_subsequence += s[i]
            i += 1
            j -= 1
        elif dp[i+1][j] > dp[i][j-1]:
            i += 1
        else:
            j -= 1

    return longest_palindrome_subsequence


# Example usage
s = "abba"
print(longest_palindrome_subsequence(s))  # Output: "abba"