📅  最后修改于: 2023-12-03 15:25:46.231000             🧑  作者: Mango
回文子序列是指一个字符串中的一部分字符按照相反的顺序排列可以得到一个和原字符串相同的字符串。比如字符串 "aba" 就是一个回文子序列。
给定一个字符串,求它的最长回文子序列,并打印出这个最长回文子序列。
这个问题可以使用动态规划的方法解决。假设 $s$ 是给定的字符串,$dp[i][j]$ 表示 $s[i:j+1]$ 中的最长回文子序列的长度。显然,$dp[i][i] = 1$,因为一个字符本身就是一个长度为 1 的回文子序列。
对于 $i < j$,如果 $s[i] = s[j]$,则 $s[i:j+1]$ 的最长回文子序列的长度为 $dp[i+1][j-1] + 2$,其中 $dp[i+1][j-1]$ 表示 $s[i+1:j]$ 中的最长回文子序列的长度。
如果 $s[i] \neq s[j]$,则 $s[i:j+1]$ 的最长回文子序列的长度为 $\max(dp[i+1][j], dp[i][j-1])$,其中 $dp[i+1][j]$ 表示 $s[i+1:j+1]$ 中的最长回文子序列的长度,$dp[i][j-1]$ 表示 $s[i:j]$ 中的最长回文子序列的长度。
最后返回 $dp[0][n-1]$ 即可,其中 $n$ 是字符串的长度。
要打印最长回文子序列,可以根据 dp 数组回溯出一个回文子序列。设 $i$ 和 $j$ 分别为最长回文子序列的起始位置和结束位置,如果 $s[i] = s[j]$,则最长回文子序列的第一个字符和最后一个字符都是 $s[i]$,于是打印出 $s[i]$。否则,如果 $dp[i+1][j] > dp[i][j-1]$,则最长回文子序列的长度来自 $s[i+1:j+1]$,于是将 $i$ 增加 1,继续寻找更短的最长回文子序列;否则,将 $j$ 减少 1。
下面是 Python 代码实现:
def longestPalindrome(s: str) -> str:
n = len(s)
dp = [[0] * n for _ in range(n)]
for i in range(n):
dp[i][i] = 1
for i in range(n-2, -1, -1):
for j in range(i+1, n):
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])
i, j = 0, n-1
res = ''
while i <= j:
if s[i] == s[j]:
res += s[i]
i += 1
j -= 1
elif dp[i+1][j] > dp[i][j-1]:
i += 1
else:
j -= 1
return res
打印最长回文子序列是一个经典的动态规划问题,可以使用 dp 数组记录状态并回溯出最长回文子序列。这个问题的时间复杂度是 $O(n^2)$,空间复杂度也是 $O(n^2)$。