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)

516. 最长回文子序列_最长回文

遍历方向:从下往上进行遍历

返回 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]