516. Longest Palindromic Subsequence

来源:互联网 发布:音序器软件中文版 编辑:程序博客网 时间:2024/05/18 01:12

题目

这里写图片描述

题意

求数组的回文子序列的最长长度

分析

f[i][j]表示从i到j的回文子序列的最长长度
转移方程如下
如果s[i]==s[j], f[i][j]=f[i+1][j1]+2
如果s[i]!=s[j], f[i][j]=max(f[i][j1],f[i+1][j])

可以理解为每次头尾扩充1个位置, 即i, j为扩充的位置, 那么涉及的子串就包括f[i+1][j1](不包括两个扩充的位置), f[i][j1] (只包括i)和 f[i+1][j](只包括j)
i==j 时 ,s[i]s[j] 可以在 f[i+1][j1] 的基础上再加上2个字符的长度;
否则, 考虑只扩充i或只扩充j的子问题, 即max(f[i][j1],f[i+1][j])

一开始我是将长度len作为外层循环, 然后里层循环是所有len的可能,代码如下

class Solution {public:    int longestPalindromeSubseq(string s) {        vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));        for (int i = 0; i < s.size(); i++) dp[i][i] = 1;        for (int len = 2; len <= s.size(); len++) {            for (int left = 0; left <= s.size()-len; left++) {                int right = left+len-1;                int temp = max(dp[left][right-1], dp[left+1][right]);                if (s[left] == s[right])                    dp[left][right] = max(dp[left+1][right-1] + 2,temp);                else                     dp[left][right] = max(dp[left+1][right-1], temp);            }        }        return dp[0][s.size()-1];    }};

但是这个开销太大了(118 ms), 按这个思路分析,
这里写图片描述
要求dp[i][j](图中棕色位置的时候)
只需要知道蓝色区域的子问题结果, 所以将循环改成

  • 外层为i从下往上
    • 内层为j从左往右

代码如下:

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