516. 最长回文子序列
方法一:递归 + 双指针
取 s 的首尾两字母 x 和 y,如果 x == y,除去 x、y 的最长回文子序列的长度 + 2,如果 x != y 除去 x 或 y 的最大的回文子序列长度中的最大值。
如: “bbbab”,“bba” 最大的回文子序列的长度 + 2,“ba” 和 “bb” 最大值是 2。
class Solution:
@lru_cache(None)
def longestPalindromeSubseq(self, s: str) -> int:
n = len(s)
if n < 2:return n
l, r = 0, len(s)-1
while l < r:
if s[l] == s[r]:
return self.longestPalindromeSubseq(s[l+1:r]) + 2
else:
return max(self.longestPalindromeSubseq(s[l+1:r+1]), self.longestPalindromeSubseq(s[l:r]))方法二:递归
对 s 中的每一个字母都要遍历,取最大值,超时。
def longestPalindromeSubseq(self, s: str) -> int:
if len(s) <= 1: return len(s)
res = 0
for i,c in enumerate(s):
r = str.rindex(s, c)
if r > i:
res = max(res, self.longestPalindromeSubseq(s[i+1:r]) + 2)
else:
res = max(res, 1)
return res方法三:递归 + 二分
class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
n = len(s)
if n <= 1: return n
cIndex = defaultdict(list)
for i, c in enumerate(s): cIndex[ord(c) - ord('a')].append(i)
@lru_cache(None)
def dfs(l, r):
if l >= r: return 1 if l == r else 0
ans = 0
for i in range(26):
left = bisect.bisect_left(cIndex[i], l)
if left == len(cIndex[i]): continue
right = bisect.bisect_left(cIndex[i], r)
print(right,)
if right == len(cIndex[i]) or cIndex[i][right] > r:
right -= 1
ans = max(ans, dfs(cIndex[i][left]+1, cIndex[i][right]-1) + 2) if right > left else max(ans, 1)
return ans
return dfs(0, n-1)方法四:动态规划
dp[i][j] 表示字符串 s 的下标区间 [i, j] 内的最长回文子序列的长度。
dp = [[0] * n for _ in range(n)] # n = len(s)遍历方向:从下往上进行遍历
返回 dp[0][−1]
class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
n = len(s)
# dp = [[1 if i == j else 0 for i in range(n)] for j in range(n)]
dp = [[0] * n for _ in range(n)]
for i in range(n-1,-1,-1):
dp[i][i] = 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])
return dp[0][-1]
















