# 516. Longest Palindromic Subsequence

**<font color=red>难度: Medium</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/longest-palindromic-subsequence/

> 内容描述

```
Given a string s, find the longest palindromic subsequence's length in s. You may assume that the maximum length of s is 1000.

Example 1:
Input:

"bbbab"
Output:
4
One possible longest palindromic subsequence is "bbbb".
Example 2:
Input:

"cbbd"
Output:
2
One possible longest palindromic subsequence is "bb".
```

## 解题方案

> 思路 1
******- 时间复杂度: O(N^2)******- 空间复杂度: O(N^2)******

其实就是求s和s[::-1]的最长公共子序列

beats 49.81%


```python
class Solution:
    def longestPalindromeSubseq(self, s):
        """
        :type s: str
        :rtype: int
        """
        if s == s[::-1]:
            return len(s)
        return self.longestCommonSubsequence(s, s[::-1])

        
    def longestCommonSubsequence(self, s1, s2):  # O(mn)
        m, n = len(s1), len(s2)
        dp = [[0] * (n + 1) for i in range(m + 1)]
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if s1[i - 1] == s2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1] + 1
                else:
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
        return dp[-1][-1]
```

> 思路 2
******- 时间复杂度: O(N^2)******- 空间复杂度: O(N^2)******


记忆化搜索，Top down，beats 5.99%，有的时候又会超时过不了，奇怪

python2死都AC不了，python3偶尔能AC

```
class Solution(object):
    def longestPalindromeSubseq(self, s):
        """
        :type s: str
        :rtype: int
        """
        cache = {}
        def helper(s, i, j):
            if (i, j) in cache:
                return cache[(i,j)]
            if i > j:
                return 0
            elif i == j:
                return 1
            else:
                if s[i] == s[j]:
                    cache[(i,j)] = helper(s, i+1, j-1) + 2
                else:
                    cache[(i,j)] = max(helper(s, i, j-1), helper(s, i+1, j))
            return cache[(i,j)]
        
        return helper(s, 0, len(s)-1)
```

> 思路 3
******- 时间复杂度: O(N^2)******- 空间复杂度: O(N^2)******


改进版记忆化搜索，beats 94.01%

```python
class Solution:
    def longestPalindromeSubseq(self, s):
        """
        :type s: str
        :rtype: int
        """
        if s == s[::-1]:
            return len(s)
        cache = {}
        def helper(s):
            if s not in cache:
                max_len = 0    
                for c in set(s):
                    i, j = s.find(c), s.rfind(c)
                    max_len = max(max_len, 1 if i == j else 2 + helper(s[i+1:j]))
                cache[s] = max_len
            return cache[s]
        return helper(s)
```


> 思路 4
******- 时间复杂度: O(N^2)******- 空间复杂度: O(N^2)******

Bottom up 

DP, beats 92.51%


```python
class Solution:
    def longestPalindromeSubseq(self, s):
        """
        :type s: str
        :rtype: int
        """
        if s == s[::-1]:
            return len(s)
        dp = [[0]*len(s) for i in range(len(s))]
        for i in range(len(s)):
            dp[i][i] = 1
        for j in range(1, len(s)):
            for i in range(j-1, -1, -1):
                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]
```


> 思路 5
******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)******


dp[i] : longest palindrom subsequence start from i

这里的空间优化我确实没怎么看懂，希望有看懂的可以给我留言

beats 94.01%

```python
class Solution:
    def longestPalindromeSubseq(self, s):
        """
        :type s: str
        :rtype: int
        """
        if s == s[::-1]:
            return len(s)
        dp = [1] * len(s)
        for i in range(1, len(s)):
            length = 0
            for j in range(i-1, -1, -1):
                tmp = dp[j]
                if s[j] == s[i]:
                    dp[j] = length + 2
                length = max(length, tmp)
        return max(dp)
```

> 思路 6
******- 时间复杂度: O(N^2)******- 空间复杂度: O(N^2)******

参考[A typical way to solve *palindrome* problems](https://leetcode.com/problems/longest-palindromic-subsequence/discuss/99118/A-typical-way-to-solve-*palindrome*-problems)

beats 88.76%

```python
class Solution:
    def longestPalindromeSubseq(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s or len(s) == 0:
            return 0
        if s == s[::-1]:
            return len(s)
        dp = [[0] * len(s) for i in range(len(s))]
        for i in range(len(s)):
            dp[i][i] = 1
        for i in range(len(s)-1):
            if s[i] == s[i+1]:
                dp[i][i+1] = 2
            else:
                dp[i][i+1] = 1

        for gap in range(2, len(s)):
            for i in range(len(s)-gap):
                j = i + gap
                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]
```




























