题目链接
https://leetcode.com/problems/longest-palindromic-subsequence/
题目描述
给定字符串s,找出其中最长的回文子序列,并返回该序列的长度。s的最大长度为1000。
示例
输入:"bbbab"
输出:4
最长回文子序列为“bbbb”
解题思路
子序列为不连续的序列,最长子序列问题常用动态规划求解。
在最长回文子序列中,定义dp数组:dp[i][j]表示子串s[i,...j](闭区间)中的最长回文子序列的长度。在动态规划中要根据较小区间范围下的结果推出较大区间范围下的结果,dp[i][j]的更新和dp[i+1][j-1]有关。
设已知dp[i+1][j-1],即子串s[i+1,...j-1](闭区间)中的最长回文子序列的长度。如果s[i]==s[j],那么s[i]和s[j]也可以加入到已知的回文子序列中。因此有dp[i][j] = dp[i+1][j-1] + 2。
如果s[i]!=s[j],那么s[i]和s[j]一定不会同时出现在s[i,...j](闭区间)的最长回文子序列中。那么s[i,...j]的最长回文子序列长度要么等于s[i+1,...j]的最长回文子序列长度,要么等于s[i,...j-1]的最长回文子序列长度,即将s[i]和s[j]分别加入子串s[i+1,...j-1]中,看哪个子串范围内的最长回文子序列更长。因此有dp[i][j] = max(dp[i+1][j],dp[i][j-1])。
base case为i=j时,dp[i][j] =1。i>j 时子序列不存在,因此dp[i][j] = 0。
由于计算dp[i][j]需要用到dp[i+1][j-1](左下角)、dp[i][j-1](左边)和dp[i-1][j](上边)的元素,因此对于二维数组dp,更新方式为从下向上,从左向右。
Python实现
class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
dp = [[0 for _ in range(len(s))] for _ in range(len(s))]
for i in range(len(s)):
dp[i][i] = 1#j = i时,最长回文子序列长度为1
for i in range(len(s)-1,-1,-1): #从下往上更新
for j in range(i+1,len(s)):#从左往右更新,仅更新j>i的部分
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])
return dp[0][len(s)-1]
时间复杂度与空间复杂度
时间复杂度为O(N^2),空间复杂度为O(N^2)。
参考
参考
https://leetcode.com/problems/longest-palindromic-subsequence/