[LeetCode] 516. 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".

 

Constraints:

  • 1 <= s.length <= 1000
  • s consists only of lowercase English letters.

 

这道题给了我们一个字符串,让求最大的回文子序列,子序列和子字符串不同,不需要连续。而关于回文串的题之前也做了不少,处理方法上就是老老实实的两两比较吧。像这种有关极值的问题,最应该优先考虑的就是贪婪算法和动态规划,这道题显然使用DP更加合适。这里建立一个二维的DP数组,其中 dp[i][j] 表示 [i,j] 区间内的字符串的最长回文子序列,那么对于递推公式分析一下,如果 s[i]==s[j],那么i和j就可以增加2个回文串的长度,我们知道中间 dp[i + 1][j - 1] 的值,那么其加上2就是 dp[i][j] 的值。如果 s[i] != s[j],就可以去掉i或j其中的一个字符,然后比较两种情况下所剩的字符串谁dp值大,就赋给 dp[i][j],那么递推公式如下:

              /  dp[i + 1][j - 1] + 2                       if (s[i] == s[j])

dp[i][j] =

              \  max(dp[i + 1][j], dp[i][j - 1])        if (s[i] != s[j])

 

解法一:

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.size();
        vector<vector<int>> dp(n, vector<int>(n));
        for (int i = n - 1; i >= 0; --i) {
            dp[i][i] = 1;
            for (int j = i + 1; j < n; ++j) {
                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][n - 1];
    }
};

 

我们可以对空间进行优化,只用一个一维的 dp 数组,参见代码如下:

 

解法二:

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.size(), res = 0;
        vector<int> dp(n, 1);
        for (int i = n - 1; i >= 0; --i) {
            int len = 0;
            for (int j = i + 1; j < n; ++j) {
                int t = dp[j];
                if (s[i] == s[j]) {
                    dp[j] = len + 2;
                } 
                len = max(len, t);
            }
        }
        for (int num : dp) res = max(res, num);
        return res;
    }
};

 

下面是递归形式的解法,memo 数组这里起到了一个缓存已经计算过了的结果,这样能提高运算效率,使其不会 TLE,参见代码如下:

 

解法三:

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.size();
        vector<vector<int>> memo(n, vector<int>(n, -1));
        return helper(s, 0, n - 1, memo);
    }
    int helper(string& s, int i, int j, vector<vector<int>>& memo) {
        if (memo[i][j] != -1) return memo[i][j];
        if (i > j) return 0;
        if (i == j) return 1;
        if (s[i] == s[j]) {
            memo[i][j] = helper(s, i + 1, j - 1, memo) + 2;
        } else {
            memo[i][j] = max(helper(s, i + 1, j, memo), helper(s, i, j - 1, memo));
        }
        return memo[i][j];
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/516

 

类似题目:

Palindromic Substrings

Longest Palindromic Substring

Count Different Palindromic Subsequences

Longest Common Subsequence

Longest Palindromic Subsequence II

 

参考资料:

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

https://leetcode.com/problems/longest-palindromic-subsequence/discuss/99101/Straight-forward-Java-DP-solution

https://leetcode.com/problems/longest-palindromic-subsequence/discuss/99158/c-beats-100-dp-solution-on2-time-on-space

 

LeetCode All in One 题目讲解汇总(持续更新中...)

posted @ 2017-03-02 23:30  Grandyang  阅读(19806)  评论(7编辑  收藏  举报
Fork me on GitHub