zoukankan      html  css  js  c++  java
  • [LeetCode] 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".

    这道题给了我们一个字符串,让我们求最大的回文子序列,子序列和子字符串不同,不需要连续。而关于回文串的题之前也做了不少,处理方法上就是老老实实的两两比较吧。像这种有关极值的问题,最应该优先考虑的就是贪婪算法和动态规划,这道题显然使用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];
        }
    };

    类似题目:

    Palindromic Substrings

    Longest Palindromic Substring

    参考资料:

    https://discuss.leetcode.com/topic/78603/straight-forward-java-dp-solution

    https://discuss.leetcode.com/topic/78799/c-beats-100-dp-solution-o-n-2-time-o-n-space

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

  • 相关阅读:
    基础篇
    模块,包
    初识面向对象
    linux在线安装jdk
    热点链接(img map area)
    oracle temp 临时表
    ajax基础代码
    Java编译执行带包名java文件
    oracle spool 用法小结
    Hadoop NameNode safemode
  • 原文地址:https://www.cnblogs.com/grandyang/p/6493182.html
Copyright © 2011-2022 走看看